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