2 Unix SMB/CIFS implementation.
4 Python interface to ntdb. Simply modified from tdb version.
6 Copyright (C) 2004-2006 Tim Potter <tpot@samba.org>
7 Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
8 Copyright (C) 2011 Rusty Russell <rusty@rustcorp.com.au>
10 ** NOTE! The following LGPL license applies to the ntdb
11 ** library. This does NOT imply that all of Samba is released
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 3 of the License, or (at your option) any later version.
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, see <http://www.gnu.org/licenses/>.
30 #include "system/filesys.h"
32 #ifndef Py_RETURN_NONE
33 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
36 /* Include ntdb headers */
41 struct ntdb_context
*ctx
;
45 staticforward PyTypeObject PyNtdb
;
47 static void PyErr_SetTDBError(enum NTDB_ERROR e
)
49 PyErr_SetObject(PyExc_RuntimeError
,
50 Py_BuildValue("(i,s)", e
, ntdb_errorstr(e
)));
53 static NTDB_DATA
PyString_AsNtdb_Data(PyObject
*data
)
56 ret
.dptr
= (unsigned char *)PyString_AsString(data
);
57 ret
.dsize
= PyString_Size(data
);
61 static PyObject
*PyString_FromNtdb_Data(NTDB_DATA data
)
63 PyObject
*ret
= PyString_FromStringAndSize((const char *)data
.dptr
,
69 #define PyErr_NTDB_ERROR_IS_ERR_RAISE(ret) \
70 if (ret != NTDB_SUCCESS) { \
71 PyErr_SetTDBError(ret); \
75 static void stderr_log(struct ntdb_context
*ntdb
,
76 enum ntdb_log_level level
,
77 enum NTDB_ERROR ecode
,
81 fprintf(stderr
, "%s:%s:%s\n",
82 ntdb_name(ntdb
), ntdb_errorstr(ecode
), message
);
85 static PyObject
*py_ntdb_open(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
88 int ntdb_flags
= NTDB_DEFAULT
, flags
= O_RDWR
, mode
= 0600;
89 struct ntdb_context
*ctx
;
91 union ntdb_attribute logattr
;
92 const char *kwnames
[] = { "name", "ntdb_flags", "flags", "mode", NULL
};
94 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|siii", cast_const2(char **, kwnames
), &name
, &ntdb_flags
, &flags
, &mode
))
98 ntdb_flags
|= NTDB_INTERNAL
;
101 logattr
.log
.base
.attr
= NTDB_ATTRIBUTE_LOG
;
102 logattr
.log
.base
.next
= NULL
;
103 logattr
.log
.fn
= stderr_log
;
104 ctx
= ntdb_open(name
, ntdb_flags
, flags
, mode
, &logattr
);
106 PyErr_SetFromErrno(PyExc_IOError
);
110 ret
= PyObject_New(PyNtdbObject
, &PyNtdb
);
118 return (PyObject
*)ret
;
121 static PyObject
*obj_transaction_cancel(PyNtdbObject
*self
)
123 ntdb_transaction_cancel(self
->ctx
);
127 static PyObject
*obj_transaction_commit(PyNtdbObject
*self
)
129 enum NTDB_ERROR ret
= ntdb_transaction_commit(self
->ctx
);
130 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
134 static PyObject
*obj_transaction_prepare_commit(PyNtdbObject
*self
)
136 enum NTDB_ERROR ret
= ntdb_transaction_prepare_commit(self
->ctx
);
137 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
141 static PyObject
*obj_transaction_start(PyNtdbObject
*self
)
143 enum NTDB_ERROR ret
= ntdb_transaction_start(self
->ctx
);
144 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
148 static PyObject
*obj_lockall(PyNtdbObject
*self
)
150 enum NTDB_ERROR ret
= ntdb_lockall(self
->ctx
);
151 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
155 static PyObject
*obj_unlockall(PyNtdbObject
*self
)
157 ntdb_unlockall(self
->ctx
);
161 static PyObject
*obj_lockall_read(PyNtdbObject
*self
)
163 enum NTDB_ERROR ret
= ntdb_lockall_read(self
->ctx
);
164 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
168 static PyObject
*obj_unlockall_read(PyNtdbObject
*self
)
170 ntdb_unlockall_read(self
->ctx
);
174 static PyObject
*obj_close(PyNtdbObject
*self
)
179 ret
= ntdb_close(self
->ctx
);
182 PyErr_SetTDBError(NTDB_ERR_IO
);
188 static PyObject
*obj_get(PyNtdbObject
*self
, PyObject
*args
)
193 if (!PyArg_ParseTuple(args
, "O", &py_key
))
196 key
= PyString_AsNtdb_Data(py_key
);
197 ret
= ntdb_fetch(self
->ctx
, key
, &data
);
198 if (ret
== NTDB_ERR_NOEXIST
)
200 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
201 return PyString_FromNtdb_Data(data
);
204 static PyObject
*obj_append(PyNtdbObject
*self
, PyObject
*args
)
207 PyObject
*py_key
, *py_data
;
209 if (!PyArg_ParseTuple(args
, "OO", &py_key
, &py_data
))
212 key
= PyString_AsNtdb_Data(py_key
);
213 data
= PyString_AsNtdb_Data(py_data
);
215 ret
= ntdb_append(self
->ctx
, key
, data
);
216 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
220 static PyObject
*obj_firstkey(PyNtdbObject
*self
)
225 ret
= ntdb_firstkey(self
->ctx
, &key
);
226 if (ret
== NTDB_ERR_NOEXIST
)
228 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
230 return PyString_FromNtdb_Data(key
);
233 static PyObject
*obj_nextkey(PyNtdbObject
*self
, PyObject
*args
)
238 if (!PyArg_ParseTuple(args
, "O", &py_key
))
241 /* Malloc here, since ntdb_nextkey frees. */
242 key
.dsize
= PyString_Size(py_key
);
243 key
.dptr
= malloc(key
.dsize
);
244 memcpy(key
.dptr
, PyString_AsString(py_key
), key
.dsize
);
246 ret
= ntdb_nextkey(self
->ctx
, &key
);
247 if (ret
== NTDB_ERR_NOEXIST
)
249 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
251 return PyString_FromNtdb_Data(key
);
254 static PyObject
*obj_delete(PyNtdbObject
*self
, PyObject
*args
)
259 if (!PyArg_ParseTuple(args
, "O", &py_key
))
262 key
= PyString_AsNtdb_Data(py_key
);
263 ret
= ntdb_delete(self
->ctx
, key
);
264 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
268 static PyObject
*obj_has_key(PyNtdbObject
*self
, PyObject
*args
)
272 if (!PyArg_ParseTuple(args
, "O", &py_key
))
275 key
= PyString_AsNtdb_Data(py_key
);
276 if (ntdb_exists(self
->ctx
, key
))
281 static PyObject
*obj_store(PyNtdbObject
*self
, PyObject
*args
)
283 NTDB_DATA key
, value
;
285 int flag
= NTDB_REPLACE
;
286 PyObject
*py_key
, *py_value
;
288 if (!PyArg_ParseTuple(args
, "OO|i", &py_key
, &py_value
, &flag
))
291 key
= PyString_AsNtdb_Data(py_key
);
292 value
= PyString_AsNtdb_Data(py_value
);
294 ret
= ntdb_store(self
->ctx
, key
, value
, flag
);
295 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
299 static PyObject
*obj_add_flag(PyNtdbObject
*self
, PyObject
*args
)
303 if (!PyArg_ParseTuple(args
, "I", &flag
))
306 ntdb_add_flag(self
->ctx
, flag
);
310 static PyObject
*obj_remove_flag(PyNtdbObject
*self
, PyObject
*args
)
314 if (!PyArg_ParseTuple(args
, "I", &flag
))
317 ntdb_remove_flag(self
->ctx
, flag
);
325 PyNtdbObject
*iteratee
;
326 } PyNtdbIteratorObject
;
328 static PyObject
*ntdb_iter_next(PyNtdbIteratorObject
*self
)
334 ret
= PyString_FromStringAndSize((const char *)self
->current
.dptr
,
335 self
->current
.dsize
);
336 e
= ntdb_nextkey(self
->iteratee
->ctx
, &self
->current
);
337 if (e
== NTDB_ERR_NOEXIST
)
340 PyErr_NTDB_ERROR_IS_ERR_RAISE(e
);
344 static void ntdb_iter_dealloc(PyNtdbIteratorObject
*self
)
346 Py_DECREF(self
->iteratee
);
350 PyTypeObject PyNtdbIterator
= {
351 .tp_name
= "Iterator",
352 .tp_basicsize
= sizeof(PyNtdbIteratorObject
),
353 .tp_iternext
= (iternextfunc
)ntdb_iter_next
,
354 .tp_dealloc
= (destructor
)ntdb_iter_dealloc
,
355 .tp_flags
= Py_TPFLAGS_DEFAULT
,
356 .tp_iter
= PyObject_SelfIter
,
359 static PyObject
*ntdb_object_iter(PyNtdbObject
*self
)
361 PyNtdbIteratorObject
*ret
;
364 ret
= PyObject_New(PyNtdbIteratorObject
, &PyNtdbIterator
);
367 e
= ntdb_firstkey(self
->ctx
, &ret
->current
);
368 if (e
== NTDB_ERR_NOEXIST
) {
371 PyErr_NTDB_ERROR_IS_ERR_RAISE(e
);
374 ret
->iteratee
= self
;
376 return (PyObject
*)ret
;
379 static PyObject
*obj_clear(PyNtdbObject
*self
)
381 enum NTDB_ERROR ret
= ntdb_wipe_all(self
->ctx
);
382 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
386 static PyObject
*obj_enable_seqnum(PyNtdbObject
*self
)
388 ntdb_add_flag(self
->ctx
, NTDB_SEQNUM
);
392 static PyMethodDef ntdb_object_methods
[] = {
393 { "transaction_cancel", (PyCFunction
)obj_transaction_cancel
, METH_NOARGS
,
394 "S.transaction_cancel() -> None\n"
395 "Cancel the currently active transaction." },
396 { "transaction_commit", (PyCFunction
)obj_transaction_commit
, METH_NOARGS
,
397 "S.transaction_commit() -> None\n"
398 "Commit the currently active transaction." },
399 { "transaction_prepare_commit", (PyCFunction
)obj_transaction_prepare_commit
, METH_NOARGS
,
400 "S.transaction_prepare_commit() -> None\n"
401 "Prepare to commit the currently active transaction" },
402 { "transaction_start", (PyCFunction
)obj_transaction_start
, METH_NOARGS
,
403 "S.transaction_start() -> None\n"
404 "Start a new transaction." },
405 { "lock_all", (PyCFunction
)obj_lockall
, METH_NOARGS
, NULL
},
406 { "unlock_all", (PyCFunction
)obj_unlockall
, METH_NOARGS
, NULL
},
407 { "read_lock_all", (PyCFunction
)obj_lockall_read
, METH_NOARGS
, NULL
},
408 { "read_unlock_all", (PyCFunction
)obj_unlockall_read
, METH_NOARGS
, NULL
},
409 { "close", (PyCFunction
)obj_close
, METH_NOARGS
, NULL
},
410 { "get", (PyCFunction
)obj_get
, METH_VARARGS
, "S.get(key) -> value\n"
412 { "append", (PyCFunction
)obj_append
, METH_VARARGS
, "S.append(key, value) -> None\n"
413 "Append data to an existing key." },
414 { "firstkey", (PyCFunction
)obj_firstkey
, METH_NOARGS
, "S.firstkey() -> data\n"
415 "Return the first key in this database." },
416 { "nextkey", (PyCFunction
)obj_nextkey
, METH_NOARGS
, "S.nextkey(key) -> data\n"
417 "Return the next key in this database." },
418 { "delete", (PyCFunction
)obj_delete
, METH_VARARGS
, "S.delete(key) -> None\n"
419 "Delete an entry." },
420 { "has_key", (PyCFunction
)obj_has_key
, METH_VARARGS
, "S.has_key(key) -> None\n"
421 "Check whether key exists in this database." },
422 { "store", (PyCFunction
)obj_store
, METH_VARARGS
, "S.store(key, data, flag=REPLACE) -> None"
424 { "add_flag", (PyCFunction
)obj_add_flag
, METH_VARARGS
, "S.add_flag(flag) -> None" },
425 { "remove_flag", (PyCFunction
)obj_remove_flag
, METH_VARARGS
, "S.remove_flag(flag) -> None" },
426 { "iterkeys", (PyCFunction
)ntdb_object_iter
, METH_NOARGS
, "S.iterkeys() -> iterator" },
427 { "clear", (PyCFunction
)obj_clear
, METH_NOARGS
, "S.clear() -> None\n"
428 "Wipe the entire database." },
429 { "enable_seqnum", (PyCFunction
)obj_enable_seqnum
, METH_NOARGS
,
430 "S.enable_seqnum() -> None" },
434 static PyObject
*obj_get_flags(PyNtdbObject
*self
, void *closure
)
436 return PyInt_FromLong(ntdb_get_flags(self
->ctx
));
439 static PyObject
*obj_get_filename(PyNtdbObject
*self
, void *closure
)
441 return PyString_FromString(ntdb_name(self
->ctx
));
444 static PyObject
*obj_get_seqnum(PyNtdbObject
*self
, void *closure
)
446 return PyInt_FromLong(ntdb_get_seqnum(self
->ctx
));
450 static PyGetSetDef ntdb_object_getsetters
[] = {
451 { cast_const(char *, "flags"), (getter
)obj_get_flags
, NULL
, NULL
},
452 { cast_const(char *, "filename"), (getter
)obj_get_filename
, NULL
,
453 cast_const(char *, "The filename of this NTDB file.")},
454 { cast_const(char *, "seqnum"), (getter
)obj_get_seqnum
, NULL
, NULL
},
458 static PyObject
*ntdb_object_repr(PyNtdbObject
*self
)
460 if (ntdb_get_flags(self
->ctx
) & NTDB_INTERNAL
) {
461 return PyString_FromString("Ntdb(<internal>)");
463 return PyString_FromFormat("Ntdb('%s')", ntdb_name(self
->ctx
));
467 static void ntdb_object_dealloc(PyNtdbObject
*self
)
470 ntdb_close(self
->ctx
);
471 self
->ob_type
->tp_free(self
);
474 static PyObject
*obj_getitem(PyNtdbObject
*self
, PyObject
*key
)
479 if (!PyString_Check(key
)) {
480 PyErr_SetString(PyExc_TypeError
, "Expected string as key");
484 tkey
.dptr
= (unsigned char *)PyString_AsString(key
);
485 tkey
.dsize
= PyString_Size(key
);
487 ret
= ntdb_fetch(self
->ctx
, tkey
, &val
);
488 if (ret
== NTDB_ERR_NOEXIST
) {
489 PyErr_SetString(PyExc_KeyError
, "No such NTDB entry");
492 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
493 return PyString_FromNtdb_Data(val
);
497 static int obj_setitem(PyNtdbObject
*self
, PyObject
*key
, PyObject
*value
)
499 NTDB_DATA tkey
, tval
;
501 if (!PyString_Check(key
)) {
502 PyErr_SetString(PyExc_TypeError
, "Expected string as key");
506 tkey
= PyString_AsNtdb_Data(key
);
509 ret
= ntdb_delete(self
->ctx
, tkey
);
511 if (!PyString_Check(value
)) {
512 PyErr_SetString(PyExc_TypeError
, "Expected string as value");
516 tval
= PyString_AsNtdb_Data(value
);
518 ret
= ntdb_store(self
->ctx
, tkey
, tval
, NTDB_REPLACE
);
521 if (ret
!= NTDB_SUCCESS
) {
522 PyErr_SetTDBError(ret
);
529 static PyMappingMethods ntdb_object_mapping
= {
530 .mp_subscript
= (binaryfunc
)obj_getitem
,
531 .mp_ass_subscript
= (objobjargproc
)obj_setitem
,
533 static PyTypeObject PyNtdb
= {
534 .tp_name
= "ntdb.Ntdb",
535 .tp_basicsize
= sizeof(PyNtdbObject
),
536 .tp_methods
= ntdb_object_methods
,
537 .tp_getset
= ntdb_object_getsetters
,
538 .tp_new
= py_ntdb_open
,
539 .tp_doc
= "A NTDB file",
540 .tp_repr
= (reprfunc
)ntdb_object_repr
,
541 .tp_dealloc
= (destructor
)ntdb_object_dealloc
,
542 .tp_as_mapping
= &ntdb_object_mapping
,
543 .tp_flags
= Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
|Py_TPFLAGS_HAVE_ITER
,
544 .tp_iter
= (getiterfunc
)ntdb_object_iter
,
547 static PyMethodDef ntdb_methods
[] = {
548 { "open", (PyCFunction
)py_ntdb_open
, METH_VARARGS
|METH_KEYWORDS
, "open(name, hash_size=0, ntdb_flags=NTDB_DEFAULT, flags=O_RDWR, mode=0600)\n"
549 "Open a NTDB file." },
558 if (PyType_Ready(&PyNtdb
) < 0)
561 if (PyType_Ready(&PyNtdbIterator
) < 0)
564 m
= Py_InitModule3("ntdb", ntdb_methods
, "NTDB is a simple key-value database similar to GDBM that supports multiple writers.");
568 PyModule_AddObject(m
, "REPLACE", PyInt_FromLong(NTDB_REPLACE
));
569 PyModule_AddObject(m
, "INSERT", PyInt_FromLong(NTDB_INSERT
));
570 PyModule_AddObject(m
, "MODIFY", PyInt_FromLong(NTDB_MODIFY
));
572 PyModule_AddObject(m
, "DEFAULT", PyInt_FromLong(NTDB_DEFAULT
));
573 PyModule_AddObject(m
, "INTERNAL", PyInt_FromLong(NTDB_INTERNAL
));
574 PyModule_AddObject(m
, "NOLOCK", PyInt_FromLong(NTDB_NOLOCK
));
575 PyModule_AddObject(m
, "NOMMAP", PyInt_FromLong(NTDB_NOMMAP
));
576 PyModule_AddObject(m
, "CONVERT", PyInt_FromLong(NTDB_CONVERT
));
577 PyModule_AddObject(m
, "NOSYNC", PyInt_FromLong(NTDB_NOSYNC
));
578 PyModule_AddObject(m
, "SEQNUM", PyInt_FromLong(NTDB_SEQNUM
));
579 PyModule_AddObject(m
, "ALLOW_NESTING", PyInt_FromLong(NTDB_ALLOW_NESTING
));
581 PyModule_AddObject(m
, "__docformat__", PyString_FromString("restructuredText"));
583 PyModule_AddObject(m
, "__version__", PyString_FromString(PACKAGE_VERSION
));
586 PyModule_AddObject(m
, "Ntdb", (PyObject
*)&PyNtdb
);
588 Py_INCREF(&PyNtdbIterator
);