1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source3/python/py_tdb.c
2007-10-10 11:00:12 -05:00

654 lines
14 KiB
C

/*
Python wrappers for TDB module
Copyright (C) Tim Potter, 2002-2003
** NOTE! The following LGPL license applies to the tdb python
** scripting library. This does NOT imply that all of Samba is
** released under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "includes.h"
/* This symbol is used in both includes.h and Python.h which causes an
annoying compiler warning. */
#ifdef HAVE_FSTAT
#undef HAVE_FSTAT
#endif
#include "Python.h"
/* Tdb exception */
PyObject *py_tdb_error;
/* tdb handle object */
typedef struct {
PyObject_HEAD
TDB_CONTEXT *tdb;
} tdb_hnd_object;
PyTypeObject tdb_hnd_type;
PyObject *new_tdb_hnd_object(TDB_CONTEXT *tdb)
{
tdb_hnd_object *obj;
obj = PyObject_New(tdb_hnd_object, &tdb_hnd_type);
obj->tdb = tdb;
return (PyObject *)obj;
}
PyObject *py_tdb_close(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj;
if (!PyArg_ParseTuple(args, "O!", &tdb_hnd_type, &obj))
return NULL;
if (tdb_close(obj->tdb) == -1) {
obj->tdb = NULL;
PyErr_SetString(py_tdb_error, strerror(errno));
return NULL;
}
obj->tdb = NULL;
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_tdb_open(PyObject *self, PyObject *args, PyObject *kw)
{
static char *kwlist[] = { "name", "hash_size", "tdb_flags",
"open_flags", "mode", NULL };
char *name;
int hash_size = 0, flags = TDB_DEFAULT, open_flags = -1, open_mode = 0600;
TDB_CONTEXT *tdb;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|iiii", kwlist, &name, &hash_size, &flags,
&open_flags, &open_mode))
return NULL;
/* Default open_flags to read/write */
if (open_flags == -1) {
if (access(name, W_OK) == -1)
open_flags = O_RDONLY;
else
open_flags = O_RDWR;
}
if (!(tdb = tdb_open(name, hash_size, flags, open_flags, open_mode))) {
PyErr_SetString(py_tdb_error, strerror(errno));
return NULL;
}
return new_tdb_hnd_object(tdb);
}
/*
* Allow a tdb to act as a python mapping (dictionary)
*/
static int tdb_traverse_count(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
void *state)
{
/* Do nothing - tdb_traverse will return the number of records
traversed. */
return 0;
}
static int tdb_hnd_length(tdb_hnd_object *obj)
{
int result;
result = tdb_traverse(obj->tdb, tdb_traverse_count, NULL);
return result;
}
static PyObject *tdb_hnd_subscript(tdb_hnd_object *obj, PyObject *key)
{
TDB_DATA drec, krec;
PyObject *result;
if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize))
return NULL;
drec = tdb_fetch(obj->tdb, krec);
if (!drec.dptr) {
PyErr_SetString(PyExc_KeyError,
PyString_AsString(key));
return NULL;
}
result = PyString_FromStringAndSize(drec.dptr, drec.dsize);
free(drec.dptr);
return result;
}
static int tdb_ass_subscript(tdb_hnd_object *obj, PyObject *key, PyObject *value)
{
TDB_DATA krec, drec;
if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize)) {
PyErr_SetString(PyExc_TypeError,
"tdb mappings have string indices only");
return -1;
}
if (!obj->tdb) {
PyErr_SetString(
py_tdb_error, "tdb object has been closed");
return -1;
}
if (!value) {
/* Delete value */
if (tdb_delete(obj->tdb, krec) == -1) {
PyErr_SetString(PyExc_KeyError,
PyString_AsString(value));
return -1;
}
} else {
/* Set value */
if (!PyArg_Parse(value, "s#", &drec.dptr, &drec.dsize)) {
PyErr_SetString(PyExc_TypeError,
"tdb mappings have string elements only");
return -1;
}
errno = 0;
if (tdb_store(obj->tdb, krec, drec, 0) < 0 ) {
if (errno != 0)
PyErr_SetFromErrno(py_tdb_error);
else
PyErr_SetString(
py_tdb_error,
(char *)tdb_errorstr(obj->tdb));
return -1;
}
}
return 0;
}
static PyMappingMethods tdb_mapping = {
(inquiry) tdb_hnd_length,
(binaryfunc) tdb_hnd_subscript,
(objobjargproc) tdb_ass_subscript
};
/*
* Utility methods
*/
/* Return non-zero if a given key exists in the tdb */
PyObject *py_tdb_hnd_has_key(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
TDB_DATA key;
if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
return NULL;
if (!obj->tdb) {
PyErr_SetString(
py_tdb_error, "tdb object has been closed");
return NULL;
}
return PyInt_FromLong(tdb_exists(obj->tdb, key));
}
/* Return a list of keys in the tdb */
static int tdb_traverse_keys(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
void *state)
{
PyObject *key_list = (PyObject *)state;
PyList_Append(key_list,
PyString_FromStringAndSize(key.dptr, key.dsize));
return 0;
}
PyObject *py_tdb_hnd_keys(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
PyObject *key_list = PyList_New(0);
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
if (tdb_traverse(obj->tdb, tdb_traverse_keys, key_list) == -1) {
PyErr_SetString(py_tdb_error, "error traversing tdb");
Py_DECREF(key_list);
return NULL;
}
return key_list;
}
PyObject *py_tdb_hnd_first_key(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
TDB_DATA key;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
key = tdb_firstkey(obj->tdb);
return Py_BuildValue("s#", key.dptr, key.dsize);
}
PyObject *py_tdb_hnd_next_key(PyObject *self, PyObject *py_oldkey)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
TDB_DATA key, oldkey;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
if (!PyArg_Parse(py_oldkey, "s#", &oldkey.dptr, &oldkey.dsize))
return NULL;
key = tdb_nextkey(obj->tdb, oldkey);
return Py_BuildValue("s#", key.dptr, key.dsize);
}
/*
* Locking routines
*/
PyObject *py_tdb_hnd_lock_all(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
int result;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
result = tdb_lockall(obj->tdb);
return PyInt_FromLong(result != -1);
}
PyObject *py_tdb_hnd_unlock_all(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
tdb_unlockall(obj->tdb);
Py_INCREF(Py_None);
return Py_None;
}
/* Return an array of keys from a python object which must be a string or a
list of strings. */
static BOOL make_lock_list(PyObject *py_keys, TDB_DATA **keys, int *num_keys)
{
/* Are we a list or a string? */
if (!PyList_Check(py_keys) && !PyString_Check(py_keys)) {
PyErr_SetString(PyExc_TypeError, "arg must be list of string");
return False;
}
if (PyList_Check(py_keys)) {
int i;
/* Turn python list into array of keys */
*num_keys = PyList_Size(py_keys);
*keys = (TDB_DATA *)SMB_XMALLOC_ARRAY(TDB_DATA, (*num_keys));
for (i = 0; i < *num_keys; i++) {
PyObject *key = PyList_GetItem(py_keys, i);
if (!PyString_Check(key)) {
PyErr_SetString(
PyExc_TypeError,
"list elements must be strings");
return False;
}
PyArg_Parse(key, "s#", &(*keys)[i].dptr,
&(*keys)[i].dsize);
}
} else {
/* Turn python string into a single key */
*keys = (TDB_DATA *)SMB_XMALLOC_P(TDB_DATA);
*num_keys = 1;
PyArg_Parse(py_keys, "s#", &(*keys)->dptr, &(*keys)->dsize);
}
return True;
}
/*
* tdb traversal
*/
struct traverse_info {
PyObject *callback;
PyObject *state;
};
static int tdb_traverse_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
void *state)
{
struct traverse_info *info = state;
PyObject *arglist, *py_result;
int result;
arglist = Py_BuildValue("(s#s#O)", key.dptr, key.dsize, value.dptr,
value.dsize, info->state);
py_result = PyEval_CallObject(info->callback, arglist);
Py_DECREF(arglist);
if (!PyInt_Check(py_result)) {
result = 1; /* Hmm - non-integer object returned by callback */
goto done;
}
result = PyInt_AsLong(py_result);
done:
Py_DECREF(py_result);
return result;
}
PyObject *py_tdb_hnd_traverse(PyObject *self, PyObject *args, PyObject *kw)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
static char *kwlist[] = { "traverse_fn", "state", NULL };
PyObject *state = Py_None, *callback;
struct traverse_info info;
int result;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O|O", kwlist, &callback, &state))
return NULL;
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return NULL;
}
Py_INCREF(callback);
Py_INCREF(state);
info.callback = callback;
info.state = state;
result = tdb_traverse(obj->tdb, tdb_traverse_traverse, &info);
Py_DECREF(callback);
Py_DECREF(state);
return PyInt_FromLong(result);
}
PyObject *py_tdb_hnd_chainlock(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
TDB_DATA key;
int result;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
return NULL;
result = tdb_chainlock(obj->tdb, key);
return PyInt_FromLong(result != -1);
}
PyObject *py_tdb_hnd_chainunlock(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
TDB_DATA key;
int result;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
return NULL;
result = tdb_chainunlock(obj->tdb, key);
return PyInt_FromLong(result != -1);
}
PyObject *py_tdb_hnd_lock_bystring(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
int result, timeout = 30;
char *s;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
if (!PyArg_ParseTuple(args, "s|i", &s, &timeout))
return NULL;
result = tdb_lock_bystring(obj->tdb, s, timeout);
return PyInt_FromLong(result != -1);
}
PyObject *py_tdb_hnd_unlock_bystring(PyObject *self, PyObject *args)
{
tdb_hnd_object *obj = (tdb_hnd_object *)self;
char *s;
if (!obj->tdb) {
PyErr_SetString(py_tdb_error, "tdb object has been closed");
return NULL;
}
if (!PyArg_ParseTuple(args, "s", &s))
return NULL;
tdb_unlock_bystring(obj->tdb, s);
Py_INCREF(Py_None);
return Py_None;
}
/*
* Method dispatch table for this module
*/
static PyMethodDef tdb_methods[] = {
{ "open", (PyCFunction)py_tdb_open, METH_VARARGS | METH_KEYWORDS },
{ "close", (PyCFunction)py_tdb_close, METH_VARARGS },
{ NULL }
};
/*
* Methods on a tdb object
*/
static PyMethodDef tdb_hnd_methods[] = {
{ "keys", (PyCFunction)py_tdb_hnd_keys, METH_VARARGS },
{ "has_key", (PyCFunction)py_tdb_hnd_has_key, METH_VARARGS },
{ "first_key", (PyCFunction)py_tdb_hnd_first_key, METH_VARARGS },
{ "next_key", (PyCFunction)py_tdb_hnd_next_key, METH_VARARGS },
{ "lock_all", (PyCFunction)py_tdb_hnd_lock_all, METH_VARARGS },
{ "unlock_all", (PyCFunction)py_tdb_hnd_unlock_all, METH_VARARGS },
{ "traverse", (PyCFunction)py_tdb_hnd_traverse, METH_VARARGS | METH_KEYWORDS },
{ "chainlock", (PyCFunction)py_tdb_hnd_chainlock, METH_VARARGS | METH_KEYWORDS },
{ "chainunlock", (PyCFunction)py_tdb_hnd_chainunlock, METH_VARARGS | METH_KEYWORDS },
{ "lock_bystring", (PyCFunction)py_tdb_hnd_lock_bystring, METH_VARARGS | METH_KEYWORDS },
{ "unlock_bystring", (PyCFunction)py_tdb_hnd_unlock_bystring, METH_VARARGS | METH_KEYWORDS },
{ NULL }
};
/* Deallocate a tdb handle object */
static void tdb_hnd_dealloc(PyObject* self)
{
tdb_hnd_object *hnd = (tdb_hnd_object *)self;
if (hnd->tdb) {
tdb_close(hnd->tdb);
hnd->tdb = NULL;
}
}
/* Return tdb handle attributes */
static PyObject *tdb_hnd_getattr(PyObject *self, char *attrname)
{
return Py_FindMethod(tdb_hnd_methods, self, attrname);
}
static char tdb_hnd_type_doc[] =
"Python wrapper for tdb.";
PyTypeObject tdb_hnd_type = {
PyObject_HEAD_INIT(NULL)
0,
"tdb",
sizeof(tdb_hnd_object),
0,
tdb_hnd_dealloc, /* tp_dealloc*/
0, /* tp_print*/
tdb_hnd_getattr, /* tp_getattr*/
0, /* tp_setattr*/
0, /* tp_compare*/
0, /* tp_repr*/
0, /* tp_as_number*/
0, /* tp_as_sequence*/
&tdb_mapping, /* tp_as_mapping*/
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /* tp_flags */
tdb_hnd_type_doc, /* tp_doc */
};
/* Constants */
static struct const_vals {
char *name;
uint32 value;
} module_const_vals[] = {
/* Flags for tdb_open() */
{ "TDB_DEFAULT", TDB_DEFAULT },
{ "TDB_CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST },
{ "TDB_INTERNAL", TDB_INTERNAL },
{ "TDB_NOLOCK", TDB_NOLOCK },
{ "TDB_NOMMAP", TDB_NOMMAP },
{ "TDB_CONVERT", TDB_CONVERT },
{ "TDB_BIGENDIAN", TDB_BIGENDIAN },
{ NULL },
};
static void const_init(PyObject *dict)
{
struct const_vals *tmp;
PyObject *obj;
for (tmp = module_const_vals; tmp->name; tmp++) {
obj = PyInt_FromLong(tmp->value);
PyDict_SetItemString(dict, tmp->name, obj);
Py_DECREF(obj);
}
}
/* Module initialisation */
void inittdb(void)
{
PyObject *module, *dict;
/* Initialise module */
module = Py_InitModule("tdb", tdb_methods);
dict = PyModule_GetDict(module);
py_tdb_error = PyErr_NewException("tdb.error", NULL, NULL);
PyDict_SetItemString(dict, "error", py_tdb_error);
/* Initialise policy handle object */
tdb_hnd_type.ob_type = &PyType_Type;
PyDict_SetItemString(dict, "tdb.hnd",
(PyObject *)&tdb_hnd_type);
/* Initialise constants */
const_init(dict);
}