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