mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
982bc5f569
(This used to be commit 0a9395bb48
)
654 lines
14 KiB
C
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);
|
|
}
|