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 38PyObject *py_tdb_error; 39 40/* tdb handle object */ 41 42typedef struct { 43 PyObject_HEAD 44 TDB_CONTEXT *tdb; 45} tdb_hnd_object; 46 47PyTypeObject tdb_hnd_type; 48 49PyObject *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 59PyObject *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 78PyObject *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 112static 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 121static 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 130static 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 152static 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 205static 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 217PyObject *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 236static 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 247PyObject *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 266PyObject *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 281PyObject *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 303PyObject *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 318PyObject *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 336static 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 *)SMB_XMALLOC_ARRAY(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 *)SMB_XMALLOC_P(TDB_DATA); 372 *num_keys = 1; 373 PyArg_Parse(py_keys, "s#", &(*keys)->dptr, &(*keys)->dsize); 374 } 375 376 return True; 377} 378 379/* 380 * tdb traversal 381 */ 382 383struct traverse_info { 384 PyObject *callback; 385 PyObject *state; 386}; 387 388static int tdb_traverse_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, 389 void *state) 390{ 391 struct traverse_info *info = state; 392 PyObject *arglist, *py_result; 393 int result; 394 395 arglist = Py_BuildValue("(s#s#O)", key.dptr, key.dsize, value.dptr, 396 value.dsize, info->state); 397 398 py_result = PyEval_CallObject(info->callback, arglist); 399 400 Py_DECREF(arglist); 401 402 if (!PyInt_Check(py_result)) { 403 result = 1; /* Hmm - non-integer object returned by callback */ 404 goto done; 405 } 406 407 result = PyInt_AsLong(py_result); 408 409done: 410 Py_DECREF(py_result); 411 return result; 412} 413 414PyObject *py_tdb_hnd_traverse(PyObject *self, PyObject *args, PyObject *kw) 415{ 416 tdb_hnd_object *obj = (tdb_hnd_object *)self; 417 static char *kwlist[] = { "traverse_fn", "state", NULL }; 418 PyObject *state = Py_None, *callback; 419 struct traverse_info info; 420 int result; 421 422 if (!PyArg_ParseTupleAndKeywords( 423 args, kw, "O|O", kwlist, &callback, &state)) 424 return NULL; 425 426 if (!PyCallable_Check(callback)) { 427 PyErr_SetString(PyExc_TypeError, "parameter must be callable"); 428 return NULL; 429 } 430 431 Py_INCREF(callback); 432 Py_INCREF(state); 433 434 info.callback = callback; 435 info.state = state; 436 437 result = tdb_traverse(obj->tdb, tdb_traverse_traverse, &info); 438 439 Py_DECREF(callback); 440 Py_DECREF(state); 441 442 return PyInt_FromLong(result); 443} 444 445PyObject *py_tdb_hnd_chainlock(PyObject *self, PyObject *args) 446{ 447 tdb_hnd_object *obj = (tdb_hnd_object *)self; 448 TDB_DATA key; 449 int result; 450 451 if (!obj->tdb) { 452 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 453 return NULL; 454 } 455 456 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize)) 457 return NULL; 458 459 result = tdb_chainlock(obj->tdb, key); 460 461 return PyInt_FromLong(result != -1); 462} 463 464PyObject *py_tdb_hnd_chainunlock(PyObject *self, PyObject *args) 465{ 466 tdb_hnd_object *obj = (tdb_hnd_object *)self; 467 TDB_DATA key; 468 int result; 469 470 if (!obj->tdb) { 471 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 472 return NULL; 473 } 474 475 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize)) 476 return NULL; 477 478 result = tdb_chainunlock(obj->tdb, key); 479 480 return PyInt_FromLong(result != -1); 481} 482 483PyObject *py_tdb_hnd_lock_bystring(PyObject *self, PyObject *args) 484{ 485 tdb_hnd_object *obj = (tdb_hnd_object *)self; 486 int result, timeout = 30; 487 char *s; 488 489 if (!obj->tdb) { 490 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 491 return NULL; 492 } 493 494 if (!PyArg_ParseTuple(args, "s|i", &s, &timeout)) 495 return NULL; 496 497 result = tdb_lock_bystring_with_timeout(obj->tdb, s, timeout); 498 499 return PyInt_FromLong(result != -1); 500} 501 502PyObject *py_tdb_hnd_unlock_bystring(PyObject *self, PyObject *args) 503{ 504 tdb_hnd_object *obj = (tdb_hnd_object *)self; 505 char *s; 506 507 if (!obj->tdb) { 508 PyErr_SetString(py_tdb_error, "tdb object has been closed"); 509 return NULL; 510 } 511 512 if (!PyArg_ParseTuple(args, "s", &s)) 513 return NULL; 514 515 tdb_unlock_bystring(obj->tdb, s); 516 517 Py_INCREF(Py_None); 518 return Py_None; 519} 520 521/* 522 * Method dispatch table for this module 523 */ 524 525static PyMethodDef tdb_methods[] = { 526 { "open", (PyCFunction)py_tdb_open, METH_VARARGS | METH_KEYWORDS }, 527 { "close", (PyCFunction)py_tdb_close, METH_VARARGS }, 528 { NULL } 529}; 530 531/* 532 * Methods on a tdb object 533 */ 534 535static PyMethodDef tdb_hnd_methods[] = { 536 { "keys", (PyCFunction)py_tdb_hnd_keys, METH_VARARGS }, 537 { "has_key", (PyCFunction)py_tdb_hnd_has_key, METH_VARARGS }, 538 { "first_key", (PyCFunction)py_tdb_hnd_first_key, METH_VARARGS }, 539 { "next_key", (PyCFunction)py_tdb_hnd_next_key, METH_VARARGS }, 540 { "lock_all", (PyCFunction)py_tdb_hnd_lock_all, METH_VARARGS }, 541 { "unlock_all", (PyCFunction)py_tdb_hnd_unlock_all, METH_VARARGS }, 542 { "traverse", (PyCFunction)py_tdb_hnd_traverse, METH_VARARGS | METH_KEYWORDS }, 543 { "chainlock", (PyCFunction)py_tdb_hnd_chainlock, METH_VARARGS | METH_KEYWORDS }, 544 { "chainunlock", (PyCFunction)py_tdb_hnd_chainunlock, METH_VARARGS | METH_KEYWORDS }, 545 { "lock_bystring", (PyCFunction)py_tdb_hnd_lock_bystring, METH_VARARGS | METH_KEYWORDS }, 546 { "unlock_bystring", (PyCFunction)py_tdb_hnd_unlock_bystring, METH_VARARGS | METH_KEYWORDS }, 547 { NULL } 548}; 549 550/* Deallocate a tdb handle object */ 551 552static void tdb_hnd_dealloc(PyObject* self) 553{ 554 tdb_hnd_object *hnd = (tdb_hnd_object *)self; 555 556 if (hnd->tdb) { 557 tdb_close(hnd->tdb); 558 hnd->tdb = NULL; 559 } 560} 561 562/* Return tdb handle attributes */ 563 564static PyObject *tdb_hnd_getattr(PyObject *self, char *attrname) 565{ 566 return Py_FindMethod(tdb_hnd_methods, self, attrname); 567} 568 569static char tdb_hnd_type_doc[] = 570"Python wrapper for tdb."; 571 572PyTypeObject tdb_hnd_type = { 573 PyObject_HEAD_INIT(NULL) 574 0, 575 "tdb", 576 sizeof(tdb_hnd_object), 577 0, 578 tdb_hnd_dealloc, /* tp_dealloc*/ 579 0, /* tp_print*/ 580 tdb_hnd_getattr, /* tp_getattr*/ 581 0, /* tp_setattr*/ 582 0, /* tp_compare*/ 583 0, /* tp_repr*/ 584 0, /* tp_as_number*/ 585 0, /* tp_as_sequence*/ 586 &tdb_mapping, /* tp_as_mapping*/ 587 0, /* tp_hash */ 588 0, /* tp_call */ 589 0, /* tp_str */ 590 0, /* tp_getattro */ 591 0, /* tp_setattro */ 592 0, /* tp_as_buffer*/ 593 Py_TPFLAGS_DEFAULT, /* tp_flags */ 594 tdb_hnd_type_doc, /* tp_doc */ 595}; 596 597/* Constants */ 598 599static struct const_vals { 600 char *name; 601 uint32 value; 602} module_const_vals[] = { 603 604 /* Flags for tdb_open() */ 605 606 { "TDB_DEFAULT", TDB_DEFAULT }, 607 { "TDB_CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST }, 608 { "TDB_INTERNAL", TDB_INTERNAL }, 609 { "TDB_NOLOCK", TDB_NOLOCK }, 610 { "TDB_NOMMAP", TDB_NOMMAP }, 611 { "TDB_CONVERT", TDB_CONVERT }, 612 { "TDB_BIGENDIAN", TDB_BIGENDIAN }, 613 614 { NULL }, 615}; 616 617static void const_init(PyObject *dict) 618{ 619 struct const_vals *tmp; 620 PyObject *obj; 621 622 for (tmp = module_const_vals; tmp->name; tmp++) { 623 obj = PyInt_FromLong(tmp->value); 624 PyDict_SetItemString(dict, tmp->name, obj); 625 Py_DECREF(obj); 626 } 627} 628 629/* Module initialisation */ 630 631void inittdb(void) 632{ 633 PyObject *module, *dict; 634 635 /* Initialise module */ 636 637 module = Py_InitModule("tdb", tdb_methods); 638 dict = PyModule_GetDict(module); 639 640 py_tdb_error = PyErr_NewException("tdb.error", NULL, NULL); 641 PyDict_SetItemString(dict, "error", py_tdb_error); 642 643 /* Initialise policy handle object */ 644 645 tdb_hnd_type.ob_type = &PyType_Type; 646 647 PyDict_SetItemString(dict, "tdb.hnd", 648 (PyObject *)&tdb_hnd_type); 649 650 /* Initialise constants */ 651 652 const_init(dict); 653} 654