]> git.ozlabs.org Git - ccan/blob - ccan/ntdb/pyntdb.c
ntdb: next-generation trivial key-value database
[ccan] / ccan / ntdb / pyntdb.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Python interface to ntdb.  Simply modified from tdb version.
5
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>
9
10      ** NOTE! The following LGPL license applies to the ntdb
11      ** library. This does NOT imply that all of Samba is released
12      ** under the LGPL
13
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.
18
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.
23
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/>.
26 */
27
28 #include <Python.h>
29 #include "replace.h"
30 #include "system/filesys.h"
31
32 /* Include ntdb headers */
33 #include <ntdb.h>
34
35 typedef struct {
36         PyObject_HEAD
37         struct ntdb_context *ctx;
38         bool closed;
39 } PyNtdbObject;
40
41 static PyTypeObject PyNtdb;
42
43 static void PyErr_SetTDBError(enum NTDB_ERROR e)
44 {
45         PyErr_SetObject(PyExc_RuntimeError,
46                 Py_BuildValue("(i,s)", e, ntdb_errorstr(e)));
47 }
48
49 static NTDB_DATA PyString_AsNtdb_Data(PyObject *data)
50 {
51         NTDB_DATA ret;
52         ret.dptr = (unsigned char *)PyString_AsString(data);
53         ret.dsize = PyString_Size(data);
54         return ret;
55 }
56
57 static PyObject *PyString_FromNtdb_Data(NTDB_DATA data)
58 {
59         PyObject *ret = PyString_FromStringAndSize((const char *)data.dptr,
60                                                    data.dsize);
61         free(data.dptr);
62         return ret;
63 }
64
65 #define PyErr_NTDB_ERROR_IS_ERR_RAISE(ret) \
66         if (ret != NTDB_SUCCESS) { \
67                 PyErr_SetTDBError(ret); \
68                 return NULL; \
69         }
70
71 #define PyNtdb_CHECK_CLOSED(pyobj) \
72         if (pyobj->closed) {\
73                 PyErr_SetObject(PyExc_RuntimeError, \
74                         Py_BuildValue("(i,s)", NTDB_ERR_EINVAL, "database is closed")); \
75                 return NULL; \
76         }
77
78 static void stderr_log(struct ntdb_context *ntdb,
79                        enum ntdb_log_level level,
80                        enum NTDB_ERROR ecode,
81                        const char *message,
82                        void *data)
83 {
84         fprintf(stderr, "%s:%s:%s\n",
85                 ntdb_name(ntdb), ntdb_errorstr(ecode), message);
86 }
87
88 static PyObject *py_ntdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
89 {
90         char *name = NULL;
91         int ntdb_flags = NTDB_DEFAULT, flags = O_RDWR, mode = 0600;
92         struct ntdb_context *ctx;
93         PyNtdbObject *ret;
94         union ntdb_attribute logattr;
95         const char *kwnames[] = { "name", "ntdb_flags", "flags", "mode", NULL };
96
97         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siii", cast_const2(char **, kwnames), &name, &ntdb_flags, &flags, &mode))
98                 return NULL;
99
100         if (name == NULL) {
101                 ntdb_flags |= NTDB_INTERNAL;
102                 name = "<internal>";
103         }
104
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);
109         if (ctx == NULL) {
110                 PyErr_SetFromErrno(PyExc_IOError);
111                 return NULL;
112         }
113
114         ret = PyObject_New(PyNtdbObject, &PyNtdb);
115         if (!ret) {
116                 ntdb_close(ctx);
117                 return NULL;
118         }
119
120         ret->ctx = ctx;
121         ret->closed = false;
122         return (PyObject *)ret;
123 }
124
125 static PyObject *obj_transaction_cancel(PyNtdbObject *self)
126 {
127         PyNtdb_CHECK_CLOSED(self);
128         ntdb_transaction_cancel(self->ctx);
129         Py_RETURN_NONE;
130 }
131
132 static PyObject *obj_transaction_commit(PyNtdbObject *self)
133 {
134         enum NTDB_ERROR ret;
135         PyNtdb_CHECK_CLOSED(self);
136         ret = ntdb_transaction_commit(self->ctx);
137         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
138         Py_RETURN_NONE;
139 }
140
141 static PyObject *obj_transaction_prepare_commit(PyNtdbObject *self)
142 {
143         enum NTDB_ERROR ret;
144         PyNtdb_CHECK_CLOSED(self);
145         ret = ntdb_transaction_prepare_commit(self->ctx);
146         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
147         Py_RETURN_NONE;
148 }
149
150 static PyObject *obj_transaction_start(PyNtdbObject *self)
151 {
152         enum NTDB_ERROR ret;
153         PyNtdb_CHECK_CLOSED(self);
154         ret = ntdb_transaction_start(self->ctx);
155         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
156         Py_RETURN_NONE;
157 }
158
159 static PyObject *obj_lockall(PyNtdbObject *self)
160 {
161         enum NTDB_ERROR ret;
162         PyNtdb_CHECK_CLOSED(self);
163         ret = ntdb_lockall(self->ctx);
164         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
165         Py_RETURN_NONE;
166 }
167
168 static PyObject *obj_unlockall(PyNtdbObject *self)
169 {
170         PyNtdb_CHECK_CLOSED(self);
171         ntdb_unlockall(self->ctx);
172         Py_RETURN_NONE;
173 }
174
175 static PyObject *obj_lockall_read(PyNtdbObject *self)
176 {
177         enum NTDB_ERROR ret;
178         PyNtdb_CHECK_CLOSED(self);
179         ret = ntdb_lockall_read(self->ctx);
180         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
181         Py_RETURN_NONE;
182 }
183
184 static PyObject *obj_unlockall_read(PyNtdbObject *self)
185 {
186         PyNtdb_CHECK_CLOSED(self);
187         ntdb_unlockall_read(self->ctx);
188         Py_RETURN_NONE;
189 }
190
191 static PyObject *obj_close(PyNtdbObject *self)
192 {
193         int ret;
194         if (self->closed)
195                 Py_RETURN_NONE;
196         ret = ntdb_close(self->ctx);
197         self->closed = true;
198         if (ret != 0) {
199                 PyErr_SetTDBError(NTDB_ERR_IO);
200                 return NULL;
201         }
202         Py_RETURN_NONE;
203 }
204
205 static PyObject *obj_get(PyNtdbObject *self, PyObject *args)
206 {
207         NTDB_DATA key, data;
208         PyObject *py_key;
209         enum NTDB_ERROR ret;
210
211         PyNtdb_CHECK_CLOSED(self);
212
213         if (!PyArg_ParseTuple(args, "O", &py_key))
214                 return NULL;
215
216         key = PyString_AsNtdb_Data(py_key);
217         ret = ntdb_fetch(self->ctx, key, &data);
218         if (ret == NTDB_ERR_NOEXIST)
219                 Py_RETURN_NONE;
220         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
221         return PyString_FromNtdb_Data(data);
222 }
223
224 static PyObject *obj_append(PyNtdbObject *self, PyObject *args)
225 {
226         NTDB_DATA key, data;
227         PyObject *py_key, *py_data;
228         enum NTDB_ERROR ret;
229
230         PyNtdb_CHECK_CLOSED(self);
231
232         if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
233                 return NULL;
234
235         key = PyString_AsNtdb_Data(py_key);
236         data = PyString_AsNtdb_Data(py_data);
237
238         ret = ntdb_append(self->ctx, key, data);
239         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
240         Py_RETURN_NONE;
241 }
242
243 static PyObject *obj_firstkey(PyNtdbObject *self)
244 {
245         enum NTDB_ERROR ret;
246         NTDB_DATA key;
247
248         PyNtdb_CHECK_CLOSED(self);
249
250         ret = ntdb_firstkey(self->ctx, &key);
251         if (ret == NTDB_ERR_NOEXIST)
252                 Py_RETURN_NONE;
253         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
254
255         return PyString_FromNtdb_Data(key);
256 }
257
258 static PyObject *obj_nextkey(PyNtdbObject *self, PyObject *args)
259 {
260         NTDB_DATA key;
261         PyObject *py_key;
262         enum NTDB_ERROR ret;
263
264         PyNtdb_CHECK_CLOSED(self);
265
266         if (!PyArg_ParseTuple(args, "O", &py_key))
267                 return NULL;
268
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);
273
274         ret = ntdb_nextkey(self->ctx, &key);
275         if (ret == NTDB_ERR_NOEXIST)
276                 Py_RETURN_NONE;
277         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
278
279         return PyString_FromNtdb_Data(key);
280 }
281
282 static PyObject *obj_delete(PyNtdbObject *self, PyObject *args)
283 {
284         NTDB_DATA key;
285         PyObject *py_key;
286         enum NTDB_ERROR ret;
287
288         PyNtdb_CHECK_CLOSED(self);
289
290         if (!PyArg_ParseTuple(args, "O", &py_key))
291                 return NULL;
292
293         key = PyString_AsNtdb_Data(py_key);
294         ret = ntdb_delete(self->ctx, key);
295         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
296         Py_RETURN_NONE;
297 }
298
299 static PyObject *obj_has_key(PyNtdbObject *self, PyObject *args)
300 {
301         NTDB_DATA key;
302         PyObject *py_key;
303
304         PyNtdb_CHECK_CLOSED(self);
305
306         if (!PyArg_ParseTuple(args, "O", &py_key))
307                 return NULL;
308
309         key = PyString_AsNtdb_Data(py_key);
310         if (ntdb_exists(self->ctx, key))
311                 return Py_True;
312         return Py_False;
313 }
314
315 static PyObject *obj_store(PyNtdbObject *self, PyObject *args)
316 {
317         NTDB_DATA key, value;
318         enum NTDB_ERROR ret;
319         int flag = NTDB_REPLACE;
320         PyObject *py_key, *py_value;
321         PyNtdb_CHECK_CLOSED(self);
322
323         if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
324                 return NULL;
325
326         key = PyString_AsNtdb_Data(py_key);
327         value = PyString_AsNtdb_Data(py_value);
328
329         ret = ntdb_store(self->ctx, key, value, flag);
330         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
331         Py_RETURN_NONE;
332 }
333
334 static PyObject *obj_add_flag(PyNtdbObject *self, PyObject *args)
335 {
336         unsigned flag;
337         PyNtdb_CHECK_CLOSED(self);
338
339         if (!PyArg_ParseTuple(args, "I", &flag))
340                 return NULL;
341
342         ntdb_add_flag(self->ctx, flag);
343         Py_RETURN_NONE;
344 }
345
346 static PyObject *obj_remove_flag(PyNtdbObject *self, PyObject *args)
347 {
348         unsigned flag;
349
350         PyNtdb_CHECK_CLOSED(self);
351
352         if (!PyArg_ParseTuple(args, "I", &flag))
353                 return NULL;
354
355         ntdb_remove_flag(self->ctx, flag);
356         Py_RETURN_NONE;
357 }
358
359 typedef struct {
360         PyObject_HEAD
361         NTDB_DATA current;
362         bool end;
363         PyNtdbObject *iteratee;
364 } PyNtdbIteratorObject;
365
366 static PyObject *ntdb_iter_next(PyNtdbIteratorObject *self)
367 {
368         enum NTDB_ERROR e;
369         PyObject *ret;
370         if (self->end)
371                 return NULL;
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)
376                 self->end = true;
377         else
378                 PyErr_NTDB_ERROR_IS_ERR_RAISE(e);
379         return ret;
380 }
381
382 static void ntdb_iter_dealloc(PyNtdbIteratorObject *self)
383 {
384         Py_DECREF(self->iteratee);
385         PyObject_Del(self);
386 }
387
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,
395 };
396
397 static PyObject *ntdb_object_iter(PyNtdbObject *self)
398 {
399         PyNtdbIteratorObject *ret;
400         enum NTDB_ERROR e;
401         PyNtdb_CHECK_CLOSED(self);
402
403         ret = PyObject_New(PyNtdbIteratorObject, &PyNtdbIterator);
404         if (!ret)
405                 return NULL;
406         e = ntdb_firstkey(self->ctx, &ret->current);
407         if (e == NTDB_ERR_NOEXIST) {
408                 ret->end = true;
409         } else {
410                 PyErr_NTDB_ERROR_IS_ERR_RAISE(e);
411                 ret->end = false;
412         }
413         ret->iteratee = self;
414         Py_INCREF(self);
415         return (PyObject *)ret;
416 }
417
418 static PyObject *obj_clear(PyNtdbObject *self)
419 {
420         enum NTDB_ERROR ret;
421         PyNtdb_CHECK_CLOSED(self);
422         ret = ntdb_wipe_all(self->ctx);
423         PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
424         Py_RETURN_NONE;
425 }
426
427 static PyObject *obj_enable_seqnum(PyNtdbObject *self)
428 {
429         PyNtdb_CHECK_CLOSED(self);
430         ntdb_add_flag(self->ctx, NTDB_SEQNUM);
431         Py_RETURN_NONE;
432 }
433
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"
453                 "Fetch a value." },
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"
465                 "Store data." },
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" },
473         { NULL }
474 };
475
476 static PyObject *obj_get_flags(PyNtdbObject *self, void *closure)
477 {
478         PyNtdb_CHECK_CLOSED(self);
479         return PyInt_FromLong(ntdb_get_flags(self->ctx));
480 }
481
482 static PyObject *obj_get_filename(PyNtdbObject *self, void *closure)
483 {
484         PyNtdb_CHECK_CLOSED(self);
485         return PyString_FromString(ntdb_name(self->ctx));
486 }
487
488 static PyObject *obj_get_seqnum(PyNtdbObject *self, void *closure)
489 {
490         PyNtdb_CHECK_CLOSED(self);
491         return PyInt_FromLong(ntdb_get_seqnum(self->ctx));
492 }
493
494
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 },
500         { NULL }
501 };
502
503 static PyObject *ntdb_object_repr(PyNtdbObject *self)
504 {
505         if (ntdb_get_flags(self->ctx) & NTDB_INTERNAL) {
506                 return PyString_FromString("Ntdb(<internal>)");
507         } else {
508                 return PyString_FromFormat("Ntdb('%s')", ntdb_name(self->ctx));
509         }
510 }
511
512 static void ntdb_object_dealloc(PyNtdbObject *self)
513 {
514         if (!self->closed)
515                 ntdb_close(self->ctx);
516         self->ob_type->tp_free(self);
517 }
518
519 static PyObject *obj_getitem(PyNtdbObject *self, PyObject *key)
520 {
521         NTDB_DATA tkey, val;
522         enum NTDB_ERROR ret;
523
524         PyNtdb_CHECK_CLOSED(self);
525
526         if (!PyString_Check(key)) {
527                 PyErr_SetString(PyExc_TypeError, "Expected string as key");
528                 return NULL;
529         }
530
531         tkey.dptr = (unsigned char *)PyString_AsString(key);
532         tkey.dsize = PyString_Size(key);
533
534         ret = ntdb_fetch(self->ctx, tkey, &val);
535         if (ret == NTDB_ERR_NOEXIST) {
536                 PyErr_SetString(PyExc_KeyError, "No such NTDB entry");
537                 return NULL;
538         } else {
539                 PyErr_NTDB_ERROR_IS_ERR_RAISE(ret);
540                 return PyString_FromNtdb_Data(val);
541         }
542 }
543
544 static int obj_setitem(PyNtdbObject *self, PyObject *key, PyObject *value)
545 {
546         NTDB_DATA tkey, tval;
547         enum NTDB_ERROR ret;
548         if (self->closed) {
549                 PyErr_SetObject(PyExc_RuntimeError,
550                         Py_BuildValue("(i,s)", NTDB_ERR_EINVAL, "database is closed"));
551                 return -1;
552         }
553
554         if (!PyString_Check(key)) {
555                 PyErr_SetString(PyExc_TypeError, "Expected string as key");
556                 return -1;
557         }
558
559         tkey = PyString_AsNtdb_Data(key);
560
561         if (value == NULL) {
562                 ret = ntdb_delete(self->ctx, tkey);
563         } else {
564                 if (!PyString_Check(value)) {
565                         PyErr_SetString(PyExc_TypeError, "Expected string as value");
566                         return -1;
567                 }
568
569                 tval = PyString_AsNtdb_Data(value);
570
571                 ret = ntdb_store(self->ctx, tkey, tval, NTDB_REPLACE);
572         }
573
574         if (ret != NTDB_SUCCESS) {
575                 PyErr_SetTDBError(ret);
576                 return -1;
577         }
578
579         return ret;
580 }
581
582 static PyMappingMethods ntdb_object_mapping = {
583         .mp_subscript = (binaryfunc)obj_getitem,
584         .mp_ass_subscript = (objobjargproc)obj_setitem,
585 };
586
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,
599 };
600
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." },
604         { NULL }
605 };
606
607 void initntdb(void);
608 void initntdb(void)
609 {
610         PyObject *m;
611
612         if (PyType_Ready(&PyNtdb) < 0)
613                 return;
614
615         if (PyType_Ready(&PyNtdbIterator) < 0)
616                 return;
617
618         m = Py_InitModule3("ntdb", ntdb_methods, "NTDB is a simple key-value database similar to GDBM that supports multiple writers.");
619         if (m == NULL)
620                 return;
621
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));
625
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));
634
635         PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText"));
636
637         PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION));
638
639         Py_INCREF(&PyNtdb);
640         PyModule_AddObject(m, "Ntdb", (PyObject *)&PyNtdb);
641
642         Py_INCREF(&PyNtdbIterator);
643 }