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 /* Include ntdb headers */
37 struct ntdb_context
*ctx
;
41 staticforward PyTypeObject PyNtdb
;
43 static void PyErr_SetTDBError(enum NTDB_ERROR e
)
45 PyErr_SetObject(PyExc_RuntimeError
,
46 Py_BuildValue("(i,s)", e
, ntdb_errorstr(e
)));
49 static NTDB_DATA
PyString_AsNtdb_Data(PyObject
*data
)
52 ret
.dptr
= (unsigned char *)PyString_AsString(data
);
53 ret
.dsize
= PyString_Size(data
);
57 static PyObject
*PyString_FromNtdb_Data(NTDB_DATA data
)
59 PyObject
*ret
= PyString_FromStringAndSize((const char *)data
.dptr
,
65 #define PyErr_NTDB_ERROR_IS_ERR_RAISE(ret) \
66 if (ret != NTDB_SUCCESS) { \
67 PyErr_SetTDBError(ret); \
71 #define PyNtdb_CHECK_CLOSED(pyobj) \
73 PyErr_SetObject(PyExc_RuntimeError, \
74 Py_BuildValue("(i,s)", NTDB_ERR_EINVAL, "database is closed")); \
78 static void stderr_log(struct ntdb_context
*ntdb
,
79 enum ntdb_log_level level
,
80 enum NTDB_ERROR ecode
,
84 fprintf(stderr
, "%s:%s:%s\n",
85 ntdb_name(ntdb
), ntdb_errorstr(ecode
), message
);
88 static PyObject
*py_ntdb_open(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
91 int ntdb_flags
= NTDB_DEFAULT
, flags
= O_RDWR
, mode
= 0600;
92 struct ntdb_context
*ctx
;
94 union ntdb_attribute logattr
;
95 const char *kwnames
[] = { "name", "ntdb_flags", "flags", "mode", NULL
};
97 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|siii", cast_const2(char **, kwnames
), &name
, &ntdb_flags
, &flags
, &mode
))
101 ntdb_flags
|= NTDB_INTERNAL
;
105 logattr
.log
.base
.attr
= NTDB_ATTRIBUTE_LOG
;
106 logattr
.log
.base
.next
= NULL
;
107 logattr
.log
.fn
= stderr_log
;
108 ctx
= ntdb_open(name
, ntdb_flags
, flags
, mode
, &logattr
);
110 PyErr_SetFromErrno(PyExc_IOError
);
114 ret
= PyObject_New(PyNtdbObject
, &PyNtdb
);
122 return (PyObject
*)ret
;
125 static PyObject
*obj_transaction_cancel(PyNtdbObject
*self
)
127 PyNtdb_CHECK_CLOSED(self
);
128 ntdb_transaction_cancel(self
->ctx
);
132 static PyObject
*obj_transaction_commit(PyNtdbObject
*self
)
135 PyNtdb_CHECK_CLOSED(self
);
136 ret
= ntdb_transaction_commit(self
->ctx
);
137 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
141 static PyObject
*obj_transaction_prepare_commit(PyNtdbObject
*self
)
144 PyNtdb_CHECK_CLOSED(self
);
145 ret
= ntdb_transaction_prepare_commit(self
->ctx
);
146 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
150 static PyObject
*obj_transaction_start(PyNtdbObject
*self
)
153 PyNtdb_CHECK_CLOSED(self
);
154 ret
= ntdb_transaction_start(self
->ctx
);
155 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
159 static PyObject
*obj_lockall(PyNtdbObject
*self
)
162 PyNtdb_CHECK_CLOSED(self
);
163 ret
= ntdb_lockall(self
->ctx
);
164 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
168 static PyObject
*obj_unlockall(PyNtdbObject
*self
)
170 PyNtdb_CHECK_CLOSED(self
);
171 ntdb_unlockall(self
->ctx
);
175 static PyObject
*obj_lockall_read(PyNtdbObject
*self
)
178 PyNtdb_CHECK_CLOSED(self
);
179 ret
= ntdb_lockall_read(self
->ctx
);
180 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
184 static PyObject
*obj_unlockall_read(PyNtdbObject
*self
)
186 PyNtdb_CHECK_CLOSED(self
);
187 ntdb_unlockall_read(self
->ctx
);
191 static PyObject
*obj_close(PyNtdbObject
*self
)
196 ret
= ntdb_close(self
->ctx
);
199 PyErr_SetTDBError(NTDB_ERR_IO
);
205 static PyObject
*obj_get(PyNtdbObject
*self
, PyObject
*args
)
211 PyNtdb_CHECK_CLOSED(self
);
213 if (!PyArg_ParseTuple(args
, "O", &py_key
))
216 key
= PyString_AsNtdb_Data(py_key
);
217 ret
= ntdb_fetch(self
->ctx
, key
, &data
);
218 if (ret
== NTDB_ERR_NOEXIST
)
220 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
221 return PyString_FromNtdb_Data(data
);
224 static PyObject
*obj_append(PyNtdbObject
*self
, PyObject
*args
)
227 PyObject
*py_key
, *py_data
;
230 PyNtdb_CHECK_CLOSED(self
);
232 if (!PyArg_ParseTuple(args
, "OO", &py_key
, &py_data
))
235 key
= PyString_AsNtdb_Data(py_key
);
236 data
= PyString_AsNtdb_Data(py_data
);
238 ret
= ntdb_append(self
->ctx
, key
, data
);
239 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
243 static PyObject
*obj_firstkey(PyNtdbObject
*self
)
248 PyNtdb_CHECK_CLOSED(self
);
250 ret
= ntdb_firstkey(self
->ctx
, &key
);
251 if (ret
== NTDB_ERR_NOEXIST
)
253 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
255 return PyString_FromNtdb_Data(key
);
258 static PyObject
*obj_nextkey(PyNtdbObject
*self
, PyObject
*args
)
264 PyNtdb_CHECK_CLOSED(self
);
266 if (!PyArg_ParseTuple(args
, "O", &py_key
))
269 /* Malloc here, since ntdb_nextkey frees. */
270 key
.dsize
= PyString_Size(py_key
);
271 key
.dptr
= malloc(key
.dsize
);
272 memcpy(key
.dptr
, PyString_AsString(py_key
), key
.dsize
);
274 ret
= ntdb_nextkey(self
->ctx
, &key
);
275 if (ret
== NTDB_ERR_NOEXIST
)
277 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
279 return PyString_FromNtdb_Data(key
);
282 static PyObject
*obj_delete(PyNtdbObject
*self
, PyObject
*args
)
288 PyNtdb_CHECK_CLOSED(self
);
290 if (!PyArg_ParseTuple(args
, "O", &py_key
))
293 key
= PyString_AsNtdb_Data(py_key
);
294 ret
= ntdb_delete(self
->ctx
, key
);
295 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
299 static PyObject
*obj_has_key(PyNtdbObject
*self
, PyObject
*args
)
304 PyNtdb_CHECK_CLOSED(self
);
306 if (!PyArg_ParseTuple(args
, "O", &py_key
))
309 key
= PyString_AsNtdb_Data(py_key
);
310 if (ntdb_exists(self
->ctx
, key
))
315 static PyObject
*obj_store(PyNtdbObject
*self
, PyObject
*args
)
317 NTDB_DATA key
, value
;
319 int flag
= NTDB_REPLACE
;
320 PyObject
*py_key
, *py_value
;
321 PyNtdb_CHECK_CLOSED(self
);
323 if (!PyArg_ParseTuple(args
, "OO|i", &py_key
, &py_value
, &flag
))
326 key
= PyString_AsNtdb_Data(py_key
);
327 value
= PyString_AsNtdb_Data(py_value
);
329 ret
= ntdb_store(self
->ctx
, key
, value
, flag
);
330 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
334 static PyObject
*obj_add_flag(PyNtdbObject
*self
, PyObject
*args
)
337 PyNtdb_CHECK_CLOSED(self
);
339 if (!PyArg_ParseTuple(args
, "I", &flag
))
342 ntdb_add_flag(self
->ctx
, flag
);
346 static PyObject
*obj_remove_flag(PyNtdbObject
*self
, PyObject
*args
)
350 PyNtdb_CHECK_CLOSED(self
);
352 if (!PyArg_ParseTuple(args
, "I", &flag
))
355 ntdb_remove_flag(self
->ctx
, flag
);
363 PyNtdbObject
*iteratee
;
364 } PyNtdbIteratorObject
;
366 static PyObject
*ntdb_iter_next(PyNtdbIteratorObject
*self
)
372 ret
= PyString_FromStringAndSize((const char *)self
->current
.dptr
,
373 self
->current
.dsize
);
374 e
= ntdb_nextkey(self
->iteratee
->ctx
, &self
->current
);
375 if (e
== NTDB_ERR_NOEXIST
)
378 PyErr_NTDB_ERROR_IS_ERR_RAISE(e
);
382 static void ntdb_iter_dealloc(PyNtdbIteratorObject
*self
)
384 Py_DECREF(self
->iteratee
);
388 PyTypeObject PyNtdbIterator
= {
389 .tp_name
= "Iterator",
390 .tp_basicsize
= sizeof(PyNtdbIteratorObject
),
391 .tp_iternext
= (iternextfunc
)ntdb_iter_next
,
392 .tp_dealloc
= (destructor
)ntdb_iter_dealloc
,
393 .tp_flags
= Py_TPFLAGS_DEFAULT
,
394 .tp_iter
= PyObject_SelfIter
,
397 static PyObject
*ntdb_object_iter(PyNtdbObject
*self
)
399 PyNtdbIteratorObject
*ret
;
401 PyNtdb_CHECK_CLOSED(self
);
403 ret
= PyObject_New(PyNtdbIteratorObject
, &PyNtdbIterator
);
406 e
= ntdb_firstkey(self
->ctx
, &ret
->current
);
407 if (e
== NTDB_ERR_NOEXIST
) {
410 PyErr_NTDB_ERROR_IS_ERR_RAISE(e
);
413 ret
->iteratee
= self
;
415 return (PyObject
*)ret
;
418 static PyObject
*obj_clear(PyNtdbObject
*self
)
421 PyNtdb_CHECK_CLOSED(self
);
422 ret
= ntdb_wipe_all(self
->ctx
);
423 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
427 static PyObject
*obj_enable_seqnum(PyNtdbObject
*self
)
429 PyNtdb_CHECK_CLOSED(self
);
430 ntdb_add_flag(self
->ctx
, NTDB_SEQNUM
);
434 static PyMethodDef ntdb_object_methods
[] = {
435 { "transaction_cancel", (PyCFunction
)obj_transaction_cancel
, METH_NOARGS
,
436 "S.transaction_cancel() -> None\n"
437 "Cancel the currently active transaction." },
438 { "transaction_commit", (PyCFunction
)obj_transaction_commit
, METH_NOARGS
,
439 "S.transaction_commit() -> None\n"
440 "Commit the currently active transaction." },
441 { "transaction_prepare_commit", (PyCFunction
)obj_transaction_prepare_commit
, METH_NOARGS
,
442 "S.transaction_prepare_commit() -> None\n"
443 "Prepare to commit the currently active transaction" },
444 { "transaction_start", (PyCFunction
)obj_transaction_start
, METH_NOARGS
,
445 "S.transaction_start() -> None\n"
446 "Start a new transaction." },
447 { "lock_all", (PyCFunction
)obj_lockall
, METH_NOARGS
, NULL
},
448 { "unlock_all", (PyCFunction
)obj_unlockall
, METH_NOARGS
, NULL
},
449 { "read_lock_all", (PyCFunction
)obj_lockall_read
, METH_NOARGS
, NULL
},
450 { "read_unlock_all", (PyCFunction
)obj_unlockall_read
, METH_NOARGS
, NULL
},
451 { "close", (PyCFunction
)obj_close
, METH_NOARGS
, NULL
},
452 { "get", (PyCFunction
)obj_get
, METH_VARARGS
, "S.get(key) -> value\n"
454 { "append", (PyCFunction
)obj_append
, METH_VARARGS
, "S.append(key, value) -> None\n"
455 "Append data to an existing key." },
456 { "firstkey", (PyCFunction
)obj_firstkey
, METH_NOARGS
, "S.firstkey() -> data\n"
457 "Return the first key in this database." },
458 { "nextkey", (PyCFunction
)obj_nextkey
, METH_NOARGS
, "S.nextkey(key) -> data\n"
459 "Return the next key in this database." },
460 { "delete", (PyCFunction
)obj_delete
, METH_VARARGS
, "S.delete(key) -> None\n"
461 "Delete an entry." },
462 { "has_key", (PyCFunction
)obj_has_key
, METH_VARARGS
, "S.has_key(key) -> None\n"
463 "Check whether key exists in this database." },
464 { "store", (PyCFunction
)obj_store
, METH_VARARGS
, "S.store(key, data, flag=REPLACE) -> None"
466 { "add_flag", (PyCFunction
)obj_add_flag
, METH_VARARGS
, "S.add_flag(flag) -> None" },
467 { "remove_flag", (PyCFunction
)obj_remove_flag
, METH_VARARGS
, "S.remove_flag(flag) -> None" },
468 { "iterkeys", (PyCFunction
)ntdb_object_iter
, METH_NOARGS
, "S.iterkeys() -> iterator" },
469 { "clear", (PyCFunction
)obj_clear
, METH_NOARGS
, "S.clear() -> None\n"
470 "Wipe the entire database." },
471 { "enable_seqnum", (PyCFunction
)obj_enable_seqnum
, METH_NOARGS
,
472 "S.enable_seqnum() -> None" },
476 static PyObject
*obj_get_flags(PyNtdbObject
*self
, void *closure
)
478 PyNtdb_CHECK_CLOSED(self
);
479 return PyInt_FromLong(ntdb_get_flags(self
->ctx
));
482 static PyObject
*obj_get_filename(PyNtdbObject
*self
, void *closure
)
484 PyNtdb_CHECK_CLOSED(self
);
485 return PyString_FromString(ntdb_name(self
->ctx
));
488 static PyObject
*obj_get_seqnum(PyNtdbObject
*self
, void *closure
)
490 PyNtdb_CHECK_CLOSED(self
);
491 return PyInt_FromLong(ntdb_get_seqnum(self
->ctx
));
495 static PyGetSetDef ntdb_object_getsetters
[] = {
496 { cast_const(char *, "flags"), (getter
)obj_get_flags
, NULL
, NULL
},
497 { cast_const(char *, "filename"), (getter
)obj_get_filename
, NULL
,
498 cast_const(char *, "The filename of this NTDB file.")},
499 { cast_const(char *, "seqnum"), (getter
)obj_get_seqnum
, NULL
, NULL
},
503 static PyObject
*ntdb_object_repr(PyNtdbObject
*self
)
505 if (ntdb_get_flags(self
->ctx
) & NTDB_INTERNAL
) {
506 return PyString_FromString("Ntdb(<internal>)");
508 return PyString_FromFormat("Ntdb('%s')", ntdb_name(self
->ctx
));
512 static void ntdb_object_dealloc(PyNtdbObject
*self
)
515 ntdb_close(self
->ctx
);
516 self
->ob_type
->tp_free(self
);
519 static PyObject
*obj_getitem(PyNtdbObject
*self
, PyObject
*key
)
524 PyNtdb_CHECK_CLOSED(self
);
526 if (!PyString_Check(key
)) {
527 PyErr_SetString(PyExc_TypeError
, "Expected string as key");
531 tkey
.dptr
= (unsigned char *)PyString_AsString(key
);
532 tkey
.dsize
= PyString_Size(key
);
534 ret
= ntdb_fetch(self
->ctx
, tkey
, &val
);
535 if (ret
== NTDB_ERR_NOEXIST
) {
536 PyErr_SetString(PyExc_KeyError
, "No such NTDB entry");
539 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret
);
540 return PyString_FromNtdb_Data(val
);
544 static int obj_setitem(PyNtdbObject
*self
, PyObject
*key
, PyObject
*value
)
546 NTDB_DATA tkey
, tval
;
549 PyErr_SetObject(PyExc_RuntimeError
,
550 Py_BuildValue("(i,s)", NTDB_ERR_EINVAL
, "database is closed"));
554 if (!PyString_Check(key
)) {
555 PyErr_SetString(PyExc_TypeError
, "Expected string as key");
559 tkey
= PyString_AsNtdb_Data(key
);
562 ret
= ntdb_delete(self
->ctx
, tkey
);
564 if (!PyString_Check(value
)) {
565 PyErr_SetString(PyExc_TypeError
, "Expected string as value");
569 tval
= PyString_AsNtdb_Data(value
);
571 ret
= ntdb_store(self
->ctx
, tkey
, tval
, NTDB_REPLACE
);
574 if (ret
!= NTDB_SUCCESS
) {
575 PyErr_SetTDBError(ret
);
582 static PyMappingMethods ntdb_object_mapping
= {
583 .mp_subscript
= (binaryfunc
)obj_getitem
,
584 .mp_ass_subscript
= (objobjargproc
)obj_setitem
,
587 static PyTypeObject PyNtdb
= {
588 .tp_name
= "ntdb.Ntdb",
589 .tp_basicsize
= sizeof(PyNtdbObject
),
590 .tp_methods
= ntdb_object_methods
,
591 .tp_getset
= ntdb_object_getsetters
,
592 .tp_new
= py_ntdb_open
,
593 .tp_doc
= "A NTDB file",
594 .tp_repr
= (reprfunc
)ntdb_object_repr
,
595 .tp_dealloc
= (destructor
)ntdb_object_dealloc
,
596 .tp_as_mapping
= &ntdb_object_mapping
,
597 .tp_flags
= Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
|Py_TPFLAGS_HAVE_ITER
,
598 .tp_iter
= (getiterfunc
)ntdb_object_iter
,
601 static PyMethodDef ntdb_methods
[] = {
602 { "open", (PyCFunction
)py_ntdb_open
, METH_VARARGS
|METH_KEYWORDS
, "open(name, hash_size=0, ntdb_flags=NTDB_DEFAULT, flags=O_RDWR, mode=0600)\n"
603 "Open a NTDB file." },
612 if (PyType_Ready(&PyNtdb
) < 0)
615 if (PyType_Ready(&PyNtdbIterator
) < 0)
618 m
= Py_InitModule3("ntdb", ntdb_methods
, "NTDB is a simple key-value database similar to GDBM that supports multiple writers.");
622 PyModule_AddObject(m
, "REPLACE", PyInt_FromLong(NTDB_REPLACE
));
623 PyModule_AddObject(m
, "INSERT", PyInt_FromLong(NTDB_INSERT
));
624 PyModule_AddObject(m
, "MODIFY", PyInt_FromLong(NTDB_MODIFY
));
626 PyModule_AddObject(m
, "DEFAULT", PyInt_FromLong(NTDB_DEFAULT
));
627 PyModule_AddObject(m
, "INTERNAL", PyInt_FromLong(NTDB_INTERNAL
));
628 PyModule_AddObject(m
, "NOLOCK", PyInt_FromLong(NTDB_NOLOCK
));
629 PyModule_AddObject(m
, "NOMMAP", PyInt_FromLong(NTDB_NOMMAP
));
630 PyModule_AddObject(m
, "CONVERT", PyInt_FromLong(NTDB_CONVERT
));
631 PyModule_AddObject(m
, "NOSYNC", PyInt_FromLong(NTDB_NOSYNC
));
632 PyModule_AddObject(m
, "SEQNUM", PyInt_FromLong(NTDB_SEQNUM
));
633 PyModule_AddObject(m
, "ALLOW_NESTING", PyInt_FromLong(NTDB_ALLOW_NESTING
));
635 PyModule_AddObject(m
, "__docformat__", PyString_FromString("restructuredText"));
637 PyModule_AddObject(m
, "__version__", PyString_FromString(PACKAGE_VERSION
));
640 PyModule_AddObject(m
, "Ntdb", (PyObject
*)&PyNtdb
);
642 Py_INCREF(&PyNtdbIterator
);