r384: Relicense tdb python module in trunk and 3.0 branch as LGPL since the
[samba.git] / source / python / py_tdb.c
1 /* 
2    Python wrappers for TDB module
3
4    Copyright (C) Tim Potter, 2002-2003
5    
6      ** NOTE! The following LGPL license applies to the tdb python
7      ** scripting library. This does NOT imply that all of Samba is 
8      ** released under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19    
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 #include "includes.h"
26
27 /* This symbol is used in both includes.h and Python.h which causes an
28    annoying compiler warning. */
29
30 #ifdef HAVE_FSTAT
31 #undef HAVE_FSTAT
32 #endif
33
34 #include "Python.h"
35
36 /* Tdb exception */
37
38 PyObject *py_tdb_error;
39
40 /* tdb handle object */
41
42 typedef struct {
43         PyObject_HEAD
44         TDB_CONTEXT *tdb;
45 } tdb_hnd_object;
46
47 PyTypeObject tdb_hnd_type;
48      
49 PyObject *new_tdb_hnd_object(TDB_CONTEXT *tdb)
50 {
51         tdb_hnd_object *obj;
52
53         obj = PyObject_New(tdb_hnd_object, &tdb_hnd_type);
54         obj->tdb = tdb;
55
56         return (PyObject *)obj;
57 }
58
59 PyObject *py_tdb_close(PyObject *self, PyObject *args)
60 {
61         tdb_hnd_object *obj;
62
63         if (!PyArg_ParseTuple(args, "O!", &tdb_hnd_type, &obj))
64                 return NULL;
65
66         if (tdb_close(obj->tdb) == -1) {
67                 obj->tdb = NULL;
68                 PyErr_SetString(py_tdb_error, strerror(errno));
69                 return NULL;
70         }
71
72         obj->tdb = NULL;
73
74         Py_INCREF(Py_None);
75         return Py_None;
76 }
77
78 PyObject *py_tdb_open(PyObject *self, PyObject *args, PyObject *kw)
79 {
80         static char *kwlist[] = { "name", "hash_size", "tdb_flags",
81                                   "open_flags", "mode", NULL };
82         char *name;
83         int hash_size = 0, flags = TDB_DEFAULT, open_flags = -1, open_mode = 0600;      
84         TDB_CONTEXT *tdb;
85
86         if (!PyArg_ParseTupleAndKeywords(
87                     args, kw, "s|iiii", kwlist, &name, &hash_size, &flags,
88                     &open_flags, &open_mode))
89                 return NULL;
90
91         /* Default open_flags to read/write */
92
93         if (open_flags == -1) {
94                 if (access(name, W_OK) == -1)
95                         open_flags = O_RDONLY;
96                 else
97                         open_flags = O_RDWR;
98         }
99
100         if (!(tdb = tdb_open(name, hash_size, flags, open_flags, open_mode))) {
101                 PyErr_SetString(py_tdb_error, strerror(errno));
102                 return NULL;
103         }
104
105         return new_tdb_hnd_object(tdb);
106 }
107
108 /*
109  * Allow a tdb to act as a python mapping (dictionary)
110  */
111
112 static int tdb_traverse_count(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
113                               void *state)
114 {
115         /* Do nothing - tdb_traverse will return the number of records
116            traversed. */
117
118         return 0;
119 }
120
121 static int tdb_hnd_length(tdb_hnd_object *obj)
122 {
123         int result;
124
125         result = tdb_traverse(obj->tdb, tdb_traverse_count, NULL);
126
127         return result;
128 }
129
130 static PyObject *tdb_hnd_subscript(tdb_hnd_object *obj, PyObject *key)
131 {
132         TDB_DATA drec, krec;
133         PyObject *result;
134
135         if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize))
136                 return NULL;
137
138         drec = tdb_fetch(obj->tdb, krec);
139
140         if (!drec.dptr) {
141                 PyErr_SetString(PyExc_KeyError,
142                                 PyString_AsString(key));
143                 return NULL;
144         }
145
146         result = PyString_FromStringAndSize(drec.dptr, drec.dsize);
147         free(drec.dptr);
148
149         return result;
150 }
151         
152 static int tdb_ass_subscript(tdb_hnd_object *obj, PyObject *key, PyObject *value)
153 {
154         TDB_DATA krec, drec;
155
156         if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize)) {
157                 PyErr_SetString(PyExc_TypeError,
158                                 "tdb mappings have string indices only");
159                 return -1;
160         }
161
162         if (!obj->tdb) {
163                 PyErr_SetString(
164                         py_tdb_error, "tdb object has been closed"); 
165                 return -1; 
166         }
167
168         if (!value) {
169
170                 /* Delete value */
171
172                 if (tdb_delete(obj->tdb, krec) == -1) {
173                         PyErr_SetString(PyExc_KeyError,
174                                         PyString_AsString(value));
175                         return -1;
176                 }
177
178         } else {
179
180                 /* Set value */
181
182                 if (!PyArg_Parse(value, "s#", &drec.dptr, &drec.dsize)) {
183                         PyErr_SetString(PyExc_TypeError,
184                                     "tdb mappings have string elements only");
185                         return -1;
186                 }
187
188                 errno = 0;
189
190                 if (tdb_store(obj->tdb, krec, drec, 0) < 0 ) {
191                         if (errno != 0)
192                                 PyErr_SetFromErrno(py_tdb_error);
193                         else
194                                 PyErr_SetString(
195                                         py_tdb_error, 
196                                         (char *)tdb_errorstr(obj->tdb));
197
198                         return -1;
199                 }
200         }
201
202         return 0;
203
204
205 static PyMappingMethods tdb_mapping = {
206         (inquiry) tdb_hnd_length,
207         (binaryfunc) tdb_hnd_subscript,
208         (objobjargproc) tdb_ass_subscript
209 };
210
211 /*
212  * Utility methods
213  */
214
215 /* Return non-zero if a given key exists in the tdb */
216
217 PyObject *py_tdb_hnd_has_key(PyObject *self, PyObject *args)
218 {
219         tdb_hnd_object *obj = (tdb_hnd_object *)self;
220         TDB_DATA key;
221
222         if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
223                 return NULL;
224
225         if (!obj->tdb) {
226                 PyErr_SetString(
227                         py_tdb_error, "tdb object has been closed"); 
228                 return NULL;
229         }       
230
231         return PyInt_FromLong(tdb_exists(obj->tdb, key));
232 }
233
234 /* Return a list of keys in the tdb */
235
236 static int tdb_traverse_keys(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
237                              void *state)
238 {
239         PyObject *key_list = (PyObject *)state;
240
241         PyList_Append(key_list, 
242                       PyString_FromStringAndSize(key.dptr, key.dsize));
243
244         return 0;
245 }
246
247 PyObject *py_tdb_hnd_keys(PyObject *self, PyObject *args)
248 {
249         tdb_hnd_object *obj = (tdb_hnd_object *)self;
250         PyObject *key_list = PyList_New(0);
251
252         if (!obj->tdb) {
253                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
254                 return NULL;
255         }       
256
257         if (tdb_traverse(obj->tdb, tdb_traverse_keys, key_list) == -1) {
258                 PyErr_SetString(py_tdb_error, "error traversing tdb");
259                 Py_DECREF(key_list);
260                 return NULL;
261         }
262
263         return key_list;        
264 }
265
266 PyObject *py_tdb_hnd_first_key(PyObject *self, PyObject *args)
267 {
268         tdb_hnd_object *obj = (tdb_hnd_object *)self;
269         TDB_DATA key;
270
271         if (!obj->tdb) {
272                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
273                 return NULL;
274         }       
275
276         key = tdb_firstkey(obj->tdb);
277
278         return Py_BuildValue("s#", key.dptr, key.dsize);
279 }
280
281 PyObject *py_tdb_hnd_next_key(PyObject *self, PyObject *py_oldkey)
282 {
283         tdb_hnd_object *obj = (tdb_hnd_object *)self;
284         TDB_DATA key, oldkey;
285
286         if (!obj->tdb) {
287                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
288                 return NULL;
289         }       
290
291         if (!PyArg_Parse(py_oldkey, "s#", &oldkey.dptr, &oldkey.dsize))
292                 return NULL;
293
294         key = tdb_nextkey(obj->tdb, oldkey);
295
296         return Py_BuildValue("s#", key.dptr, key.dsize);
297 }
298
299 /*
300  * Locking routines
301  */
302
303 PyObject *py_tdb_hnd_lock_all(PyObject *self, PyObject *args)
304 {
305         tdb_hnd_object *obj = (tdb_hnd_object *)self;
306         int result;
307
308         if (!obj->tdb) {
309                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
310                 return NULL;
311         }       
312
313         result = tdb_lockall(obj->tdb);
314
315         return PyInt_FromLong(result != -1);
316 }
317
318 PyObject *py_tdb_hnd_unlock_all(PyObject *self, PyObject *args)
319 {
320         tdb_hnd_object *obj = (tdb_hnd_object *)self;
321
322         if (!obj->tdb) {
323                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
324                 return NULL;
325         }       
326
327         tdb_unlockall(obj->tdb);
328
329         Py_INCREF(Py_None);
330         return Py_None;
331 }
332
333 /* Return an array of keys from a python object which must be a string or a
334    list of strings. */
335
336 static BOOL make_lock_list(PyObject *py_keys, TDB_DATA **keys, int *num_keys)
337 {
338         /* Are we a list or a string? */
339
340         if (!PyList_Check(py_keys) && !PyString_Check(py_keys)) {
341                 PyErr_SetString(PyExc_TypeError, "arg must be list of string");
342                 return False;
343         }
344
345         if (PyList_Check(py_keys)) {
346                 int i;
347
348                 /* Turn python list into array of keys */
349                 
350                 *num_keys = PyList_Size(py_keys);
351                 *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA) * (*num_keys));
352                 
353                 for (i = 0; i < *num_keys; i++) {
354                         PyObject *key = PyList_GetItem(py_keys, i);
355                         
356                         if (!PyString_Check(key)) {
357                                 PyErr_SetString(
358                                         PyExc_TypeError,
359                                         "list elements must be strings");
360                                 return False;
361                         }
362
363                         PyArg_Parse(key, "s#", &(*keys)[i].dptr, 
364                                     &(*keys)[i].dsize);
365                 }
366
367         } else {
368
369                 /* Turn python string into a single key */
370
371                 *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA));
372                 *num_keys = 1;
373                 PyArg_Parse(py_keys, "s#", &(*keys)->dptr, &(*keys)->dsize);
374         }
375
376         return True;
377 }
378
379 PyObject *py_tdb_hnd_lock(PyObject *self, PyObject *args)
380 {
381         tdb_hnd_object *obj = (tdb_hnd_object *)self;
382         PyObject *py_keys;
383         TDB_DATA *keys;
384         int num_keys, result;
385
386         if (!obj->tdb) {
387                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
388                 return NULL;
389         }       
390
391         if (!PyArg_ParseTuple(args, "O", &py_keys))
392                 return NULL;
393
394         if (!make_lock_list(py_keys, &keys, &num_keys))
395                 return NULL;
396
397         result = tdb_lockkeys(obj->tdb, num_keys, keys);
398
399         free(keys);
400
401         return PyInt_FromLong(result != -1);
402 }
403
404 PyObject *py_tdb_hnd_unlock(PyObject *self, PyObject *args)
405 {
406         tdb_hnd_object *obj = (tdb_hnd_object *)self;
407         
408         if (!obj->tdb) {
409                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
410                 return NULL;
411         }       
412         
413         if (!PyArg_ParseTuple(args, ""))
414                 return NULL;
415         
416         tdb_unlockkeys(obj->tdb);
417
418         Py_INCREF(Py_None);
419         return Py_None;
420 }
421
422 /*
423  * tdb traversal
424  */
425
426 struct traverse_info {
427         PyObject *callback;
428         PyObject *state;
429 };
430
431 static int tdb_traverse_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
432                                  void *state)
433 {
434         struct traverse_info *info = state;
435         PyObject *arglist, *py_result;
436         int result;
437
438         arglist = Py_BuildValue("(s#s#O)", key.dptr, key.dsize, value.dptr,
439                                 value.dsize, info->state);
440
441         py_result = PyEval_CallObject(info->callback, arglist);
442
443         Py_DECREF(arglist);
444         
445         if (!PyInt_Check(py_result)) {
446                 result = 1;     /* Hmm - non-integer object returned by callback */
447                 goto done;
448         }
449
450         result = PyInt_AsLong(py_result);
451
452 done:
453         Py_DECREF(py_result);
454         return result;
455 }
456
457 PyObject *py_tdb_hnd_traverse(PyObject *self, PyObject *args, PyObject *kw)
458 {
459         tdb_hnd_object *obj = (tdb_hnd_object *)self;
460         static char *kwlist[] = { "traverse_fn", "state", NULL };
461         PyObject *state = Py_None, *callback;
462         struct traverse_info info;
463         int result;
464
465         if (!PyArg_ParseTupleAndKeywords(
466                     args, kw, "O|O", kwlist, &callback, &state))
467                 return NULL;
468
469         if (!PyCallable_Check(callback)) {
470                 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
471                 return NULL;
472         }
473
474         Py_INCREF(callback);
475         Py_INCREF(state);
476
477         info.callback = callback;
478         info.state = state;
479
480         result = tdb_traverse(obj->tdb, tdb_traverse_traverse, &info);
481
482         Py_DECREF(callback);
483         Py_DECREF(state);
484
485         return PyInt_FromLong(result);
486 }
487
488 PyObject *py_tdb_hnd_chainlock(PyObject *self, PyObject *args)
489 {
490         tdb_hnd_object *obj = (tdb_hnd_object *)self;
491         TDB_DATA key;
492         int result;
493
494         if (!obj->tdb) {
495                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
496                 return NULL;
497         }       
498
499         if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
500                 return NULL;
501
502         result = tdb_chainlock(obj->tdb, key);
503
504         return PyInt_FromLong(result != -1);
505 }
506
507 PyObject *py_tdb_hnd_chainunlock(PyObject *self, PyObject *args)
508 {
509         tdb_hnd_object *obj = (tdb_hnd_object *)self;
510         TDB_DATA key;
511         int result;
512
513         if (!obj->tdb) {
514                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
515                 return NULL;
516         }       
517
518         if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
519                 return NULL;
520
521         result = tdb_chainunlock(obj->tdb, key);
522
523         return PyInt_FromLong(result != -1);
524 }
525
526 PyObject *py_tdb_hnd_lock_bystring(PyObject *self, PyObject *args)
527 {
528         tdb_hnd_object *obj = (tdb_hnd_object *)self;
529         int result, timeout = 30;
530         char *s;
531
532         if (!obj->tdb) {
533                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
534                 return NULL;
535         }       
536
537         if (!PyArg_ParseTuple(args, "s|i", &s, &timeout))
538                 return NULL;
539
540         result = tdb_lock_bystring(obj->tdb, s, timeout);
541
542         return PyInt_FromLong(result != -1);
543 }
544
545 PyObject *py_tdb_hnd_unlock_bystring(PyObject *self, PyObject *args)
546 {
547         tdb_hnd_object *obj = (tdb_hnd_object *)self;
548         char *s;
549
550         if (!obj->tdb) {
551                 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
552                 return NULL;
553         }       
554
555         if (!PyArg_ParseTuple(args, "s", &s))
556                 return NULL;
557
558         tdb_unlock_bystring(obj->tdb, s);
559
560         Py_INCREF(Py_None);
561         return Py_None;
562 }
563
564 /* 
565  * Method dispatch table for this module
566  */
567
568 static PyMethodDef tdb_methods[] = {
569         { "open", (PyCFunction)py_tdb_open, METH_VARARGS | METH_KEYWORDS },
570         { "close", (PyCFunction)py_tdb_close, METH_VARARGS },
571         { NULL }
572 };
573
574 /* 
575  * Methods on a tdb object
576  */
577
578 static PyMethodDef tdb_hnd_methods[] = {
579         { "keys", (PyCFunction)py_tdb_hnd_keys, METH_VARARGS },
580         { "has_key", (PyCFunction)py_tdb_hnd_has_key, METH_VARARGS },
581         { "first_key", (PyCFunction)py_tdb_hnd_first_key, METH_VARARGS },
582         { "next_key", (PyCFunction)py_tdb_hnd_next_key, METH_VARARGS },
583         { "lock_all", (PyCFunction)py_tdb_hnd_lock_all, METH_VARARGS },
584         { "unlock_all", (PyCFunction)py_tdb_hnd_unlock_all, METH_VARARGS },
585         { "lock", (PyCFunction)py_tdb_hnd_lock, METH_VARARGS },
586         { "unlock", (PyCFunction)py_tdb_hnd_unlock, METH_VARARGS },
587         { "traverse", (PyCFunction)py_tdb_hnd_traverse, METH_VARARGS | METH_KEYWORDS },
588         { "chainlock", (PyCFunction)py_tdb_hnd_chainlock, METH_VARARGS | METH_KEYWORDS },
589         { "chainunlock", (PyCFunction)py_tdb_hnd_chainunlock, METH_VARARGS | METH_KEYWORDS },
590         { "lock_bystring", (PyCFunction)py_tdb_hnd_lock_bystring, METH_VARARGS | METH_KEYWORDS },
591         { "unlock_bystring", (PyCFunction)py_tdb_hnd_unlock_bystring, METH_VARARGS | METH_KEYWORDS },
592         { NULL }
593 };
594
595 /* Deallocate a tdb handle object */
596
597 static void tdb_hnd_dealloc(PyObject* self)
598 {
599         tdb_hnd_object *hnd = (tdb_hnd_object *)self;
600
601         if (hnd->tdb) {
602                 tdb_close(hnd->tdb);
603                 hnd->tdb = NULL;
604         }
605 }
606
607 /* Return tdb handle attributes */
608
609 static PyObject *tdb_hnd_getattr(PyObject *self, char *attrname)
610 {
611         return Py_FindMethod(tdb_hnd_methods, self, attrname);
612 }
613
614 static char tdb_hnd_type_doc[] = 
615 "Python wrapper for tdb.";
616
617 PyTypeObject tdb_hnd_type = {
618         PyObject_HEAD_INIT(NULL)
619         0,
620         "tdb",
621         sizeof(tdb_hnd_object),
622         0,
623         tdb_hnd_dealloc,        /* tp_dealloc*/
624         0,                      /* tp_print*/
625         tdb_hnd_getattr,        /* tp_getattr*/
626         0,                      /* tp_setattr*/
627         0,                      /* tp_compare*/
628         0,                      /* tp_repr*/
629         0,                      /* tp_as_number*/
630         0,                      /* tp_as_sequence*/
631         &tdb_mapping,           /* tp_as_mapping*/
632         0,                      /* tp_hash */
633         0,                      /* tp_call */
634         0,                      /* tp_str */
635         0,                      /* tp_getattro */
636         0,                      /* tp_setattro */
637         0,                      /* tp_as_buffer*/
638         Py_TPFLAGS_DEFAULT,     /* tp_flags */
639         tdb_hnd_type_doc,       /* tp_doc */
640 };
641
642 /* Constants */
643
644 static struct const_vals {
645         char *name;
646         uint32 value;
647 } module_const_vals[] = {
648
649         /* Flags for tdb_open() */
650
651         { "TDB_DEFAULT", TDB_DEFAULT },
652         { "TDB_CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST },
653         { "TDB_INTERNAL", TDB_INTERNAL },
654         { "TDB_NOLOCK", TDB_NOLOCK },
655         { "TDB_NOMMAP", TDB_NOMMAP },
656         { "TDB_CONVERT", TDB_CONVERT },
657         { "TDB_BIGENDIAN", TDB_BIGENDIAN },
658         
659         { NULL },
660 };
661
662 static void const_init(PyObject *dict)
663 {
664         struct const_vals *tmp;
665         PyObject *obj;
666
667         for (tmp = module_const_vals; tmp->name; tmp++) {
668                 obj = PyInt_FromLong(tmp->value);
669                 PyDict_SetItemString(dict, tmp->name, obj);
670                 Py_DECREF(obj);
671         }
672 }
673
674 /* Module initialisation */
675
676 void inittdb(void)
677 {
678         PyObject *module, *dict;
679
680         /* Initialise module */
681
682         module = Py_InitModule("tdb", tdb_methods);
683         dict = PyModule_GetDict(module);
684
685         py_tdb_error = PyErr_NewException("tdb.error", NULL, NULL);
686         PyDict_SetItemString(dict, "error", py_tdb_error);
687
688         /* Initialise policy handle object */
689
690         tdb_hnd_type.ob_type = &PyType_Type;
691
692         PyDict_SetItemString(dict, "tdb.hnd", 
693                              (PyObject *)&tdb_hnd_type);
694
695         /* Initialise constants */
696
697         const_init(dict);
698 }