1 /* Berkeley DB interface.
2    Author: Michael McLay
3    Hacked: Guido van Rossum
4    Btree and Recno additions plus sequence methods: David Ely
5    Hacked by Gustavo Niemeyer <niemeyer@conectiva.com> fixing recno
6    support.
7 
8    XXX To do:
9    - provide a way to access the various hash functions
10    - support more open flags
11 
12    The windows port of the Berkeley DB code is hard to find on the web:
13    www.nightmare.com/software.html
14 */
15 
16 #include "Python.h"
17 #ifdef WITH_THREAD
18 #include "pythread.h"
19 #endif
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #ifdef HAVE_DB_185_H
25 #include <db_185.h>
26 #else
27 #include <db.h>
28 #endif
29 /* Please don't include internal header files of the Berkeley db package
30    (it messes up the info required in the Setup file) */
31 
32 typedef struct {
33     PyObject_HEAD
34     DB *di_bsddb;
35     int di_size;        /* -1 means recompute */
36     int di_type;
37 #ifdef WITH_THREAD
38     PyThread_type_lock di_lock;
39 #endif
40 } bsddbobject;
41 
42 static PyTypeObject Bsddbtype;
43 
44 #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
45 #define check_bsddbobject_open(v, r) if ((v)->di_bsddb == NULL) \
46                { PyErr_SetString(BsddbError, \
47                                  "BSDDB object has already been closed"); \
48                  return r; }
49 
50 static PyObject *BsddbError;
51 
52 static PyObject *
newdbhashobject(char * file,int flags,int mode,int bsize,int ffactor,int nelem,int cachesize,int hash,int lorder)53 newdbhashobject(char *file, int flags, int mode,
54                 int bsize, int ffactor, int nelem, int cachesize,
55                 int hash, int lorder)
56 {
57     bsddbobject *dp;
58     HASHINFO info;
59 
60     if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
61         return NULL;
62 
63     info.bsize = bsize;
64     info.ffactor = ffactor;
65     info.nelem = nelem;
66     info.cachesize = cachesize;
67     info.hash = NULL; /* XXX should derive from hash argument */
68     info.lorder = lorder;
69 
70 #ifdef O_BINARY
71     flags |= O_BINARY;
72 #endif
73     Py_BEGIN_ALLOW_THREADS
74     dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info);
75     Py_END_ALLOW_THREADS
76     if (dp->di_bsddb == NULL) {
77         PyErr_SetFromErrno(BsddbError);
78 #ifdef WITH_THREAD
79         dp->di_lock = NULL;
80 #endif
81         Py_DECREF(dp);
82         return NULL;
83     }
84 
85     dp->di_size = -1;
86     dp->di_type = DB_HASH;
87 
88 #ifdef WITH_THREAD
89     dp->di_lock = PyThread_allocate_lock();
90     if (dp->di_lock == NULL) {
91         PyErr_SetString(BsddbError, "can't allocate lock");
92         Py_DECREF(dp);
93         return NULL;
94     }
95 #endif
96 
97     return (PyObject *)dp;
98 }
99 
100 static PyObject *
newdbbtobject(char * file,int flags,int mode,int btflags,int cachesize,int maxkeypage,int minkeypage,int psize,int lorder)101 newdbbtobject(char *file, int flags, int mode,
102               int btflags, int cachesize, int maxkeypage,
103               int minkeypage, int psize, int lorder)
104 {
105     bsddbobject *dp;
106     BTREEINFO info;
107 
108     if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
109         return NULL;
110 
111     info.flags = btflags;
112     info.cachesize = cachesize;
113     info.maxkeypage = maxkeypage;
114     info.minkeypage = minkeypage;
115     info.psize = psize;
116     info.lorder = lorder;
117     info.compare = 0; /* Use default comparison functions, for now..*/
118     info.prefix = 0;
119 
120 #ifdef O_BINARY
121     flags |= O_BINARY;
122 #endif
123     Py_BEGIN_ALLOW_THREADS
124     dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info);
125     Py_END_ALLOW_THREADS
126     if (dp->di_bsddb == NULL) {
127         PyErr_SetFromErrno(BsddbError);
128 #ifdef WITH_THREAD
129         dp->di_lock = NULL;
130 #endif
131         Py_DECREF(dp);
132         return NULL;
133     }
134 
135     dp->di_size = -1;
136     dp->di_type = DB_BTREE;
137 
138 #ifdef WITH_THREAD
139     dp->di_lock = PyThread_allocate_lock();
140     if (dp->di_lock == NULL) {
141         PyErr_SetString(BsddbError, "can't allocate lock");
142         Py_DECREF(dp);
143         return NULL;
144     }
145 #endif
146 
147     return (PyObject *)dp;
148 }
149 
150 static PyObject *
newdbrnobject(char * file,int flags,int mode,int rnflags,int cachesize,int psize,int lorder,size_t reclen,u_char bval,char * bfname)151 newdbrnobject(char *file, int flags, int mode,
152               int rnflags, int cachesize, int psize, int lorder,
153               size_t reclen, u_char bval, char *bfname)
154 {
155     bsddbobject *dp;
156     RECNOINFO info;
157     int fd;
158 
159     if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
160         return NULL;
161 
162     info.flags = rnflags;
163     info.cachesize = cachesize;
164     info.psize = psize;
165     info.lorder = lorder;
166     info.reclen = reclen;
167     info.bval = bval;
168     info.bfname = bfname;
169 
170 #ifdef O_BINARY
171     flags |= O_BINARY;
172 #endif
173     /* This is a hack to avoid a dbopen() bug that happens when
174      * it fails. */
175     fd = open(file, flags);
176     if (fd == -1) {
177         dp->di_bsddb = NULL;
178     }
179     else {
180         close(fd);
181         Py_BEGIN_ALLOW_THREADS
182         dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
183         Py_END_ALLOW_THREADS
184     }
185     if (dp->di_bsddb == NULL) {
186         PyErr_SetFromErrno(BsddbError);
187 #ifdef WITH_THREAD
188         dp->di_lock = NULL;
189 #endif
190         Py_DECREF(dp);
191         return NULL;
192     }
193 
194     dp->di_size = -1;
195     dp->di_type = DB_RECNO;
196 
197 #ifdef WITH_THREAD
198     dp->di_lock = PyThread_allocate_lock();
199     if (dp->di_lock == NULL) {
200         PyErr_SetString(BsddbError, "can't allocate lock");
201         Py_DECREF(dp);
202         return NULL;
203     }
204 #endif
205 
206     return (PyObject *)dp;
207 }
208 
209 static void
bsddb_dealloc(bsddbobject * dp)210 bsddb_dealloc(bsddbobject *dp)
211 {
212 #ifdef WITH_THREAD
213     if (dp->di_lock) {
214         PyThread_acquire_lock(dp->di_lock, 0);
215         PyThread_release_lock(dp->di_lock);
216         PyThread_free_lock(dp->di_lock);
217         dp->di_lock = NULL;
218     }
219 #endif
220     if (dp->di_bsddb != NULL) {
221         int status;
222         Py_BEGIN_ALLOW_THREADS
223         status = (dp->di_bsddb->close)(dp->di_bsddb);
224         Py_END_ALLOW_THREADS
225         if (status != 0)
226             fprintf(stderr,
227                 "Python bsddb: close errno %d in dealloc\n",
228                 errno);
229     }
230     PyObject_Del(dp);
231 }
232 
233 #ifdef WITH_THREAD
234 #define BSDDB_BGN_SAVE(_dp) \
235     Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
236 #define BSDDB_END_SAVE(_dp) \
237     PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
238 #else
239 #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
240 #define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
241 #endif
242 
243 static Py_ssize_t
bsddb_length(bsddbobject * dp)244 bsddb_length(bsddbobject *dp)
245 {
246     check_bsddbobject_open(dp, -1);
247     if (dp->di_size < 0) {
248         DBT krec, drec;
249         int status;
250         int size = 0;
251         BSDDB_BGN_SAVE(dp)
252         for (status = (dp->di_bsddb->seq)(dp->di_bsddb,
253                                           &krec, &drec,R_FIRST);
254              status == 0;
255              status = (dp->di_bsddb->seq)(dp->di_bsddb,
256                                           &krec, &drec, R_NEXT))
257             size++;
258         BSDDB_END_SAVE(dp)
259         if (status < 0) {
260             PyErr_SetFromErrno(BsddbError);
261             return -1;
262         }
263         dp->di_size = size;
264     }
265     return dp->di_size;
266 }
267 
268 static PyObject *
bsddb_subscript(bsddbobject * dp,PyObject * key)269 bsddb_subscript(bsddbobject *dp, PyObject *key)
270 {
271     int status;
272     DBT krec, drec;
273     char *data = NULL;
274     char buf[4096];
275     int size;
276     PyObject *result;
277     recno_t recno;
278 
279     if (dp->di_type == DB_RECNO) {
280         if (!PyArg_Parse(key, "i", &recno)) {
281             PyErr_SetString(PyExc_TypeError,
282                             "key type must be integer");
283             return NULL;
284         }
285         krec.data = &recno;
286         krec.size = sizeof(recno);
287     }
288     else {
289         if (!PyArg_Parse(key, "s#", &data, &size)) {
290             PyErr_SetString(PyExc_TypeError,
291                             "key type must be string");
292             return NULL;
293         }
294         krec.data = data;
295         krec.size = size;
296     }
297     check_bsddbobject_open(dp, NULL);
298 
299     BSDDB_BGN_SAVE(dp)
300     status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
301     if (status == 0) {
302         if (drec.size > sizeof(buf)) data = malloc(drec.size);
303         else data = buf;
304         if (data!=NULL) memcpy(data,drec.data,drec.size);
305     }
306     BSDDB_END_SAVE(dp)
307     if (data==NULL) return PyErr_NoMemory();
308     if (status != 0) {
309         if (status < 0)
310             PyErr_SetFromErrno(BsddbError);
311         else
312             PyErr_SetObject(PyExc_KeyError, key);
313         return NULL;
314     }
315 
316     result = PyString_FromStringAndSize(data, (int)drec.size);
317     if (data != buf) free(data);
318     return result;
319 }
320 
321 static int
bsddb_ass_sub(bsddbobject * dp,PyObject * key,PyObject * value)322 bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
323 {
324     int status;
325     DBT krec, drec;
326     char *data;
327     int size;
328     recno_t recno;
329 
330     if (dp->di_type == DB_RECNO) {
331         if (!PyArg_Parse(key, "i", &recno)) {
332             PyErr_SetString(PyExc_TypeError,
333                             "bsddb key type must be integer");
334             return -1;
335         }
336         krec.data = &recno;
337         krec.size = sizeof(recno);
338     }
339     else {
340         if (!PyArg_Parse(key, "s#", &data, &size)) {
341             PyErr_SetString(PyExc_TypeError,
342                             "bsddb key type must be string");
343             return -1;
344         }
345         krec.data = data;
346         krec.size = size;
347     }
348     check_bsddbobject_open(dp, -1);
349     dp->di_size = -1;
350     if (value == NULL) {
351         BSDDB_BGN_SAVE(dp)
352         status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
353         BSDDB_END_SAVE(dp)
354     }
355     else {
356         if (!PyArg_Parse(value, "s#", &data, &size)) {
357             PyErr_SetString(PyExc_TypeError,
358                             "bsddb value type must be string");
359             return -1;
360         }
361         drec.data = data;
362         drec.size = size;
363         BSDDB_BGN_SAVE(dp)
364         status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
365         BSDDB_END_SAVE(dp)
366     }
367     if (status != 0) {
368         if (status < 0)
369             PyErr_SetFromErrno(BsddbError);
370         else
371             PyErr_SetObject(PyExc_KeyError, key);
372         return -1;
373     }
374     return 0;
375 }
376 
377 static PyMappingMethods bsddb_as_mapping = {
378     (lenfunc)bsddb_length,              /*mp_length*/
379     (binaryfunc)bsddb_subscript,        /*mp_subscript*/
380     (objobjargproc)bsddb_ass_sub,       /*mp_ass_subscript*/
381 };
382 
383 static PyObject *
bsddb_close(bsddbobject * dp)384 bsddb_close(bsddbobject *dp)
385 {
386     if (dp->di_bsddb != NULL) {
387         int status;
388         BSDDB_BGN_SAVE(dp)
389         status = (dp->di_bsddb->close)(dp->di_bsddb);
390         BSDDB_END_SAVE(dp)
391         if (status != 0) {
392             dp->di_bsddb = NULL;
393             PyErr_SetFromErrno(BsddbError);
394             return NULL;
395         }
396     }
397     dp->di_bsddb = NULL;
398     Py_INCREF(Py_None);
399     return Py_None;
400 }
401 
402 static PyObject *
bsddb_keys(bsddbobject * dp)403 bsddb_keys(bsddbobject *dp)
404 {
405     PyObject *list, *item=NULL;
406     DBT krec, drec;
407     char *data=NULL,buf[4096];
408     int status;
409     int err;
410 
411     check_bsddbobject_open(dp, NULL);
412     list = PyList_New(0);
413     if (list == NULL)
414         return NULL;
415     BSDDB_BGN_SAVE(dp)
416     status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
417     if (status == 0) {
418         if (krec.size > sizeof(buf)) data = malloc(krec.size);
419         else data = buf;
420         if (data != NULL) memcpy(data,krec.data,krec.size);
421     }
422     BSDDB_END_SAVE(dp)
423     if (status == 0 && data==NULL) return PyErr_NoMemory();
424     while (status == 0) {
425         if (dp->di_type == DB_RECNO)
426             item = PyInt_FromLong(*((int*)data));
427         else
428             item = PyString_FromStringAndSize(data,
429                                               (int)krec.size);
430         if (data != buf) free(data);
431         if (item == NULL) {
432             Py_DECREF(list);
433             return NULL;
434         }
435         err = PyList_Append(list, item);
436         Py_DECREF(item);
437         if (err != 0) {
438             Py_DECREF(list);
439             return NULL;
440         }
441         BSDDB_BGN_SAVE(dp)
442         status = (dp->di_bsddb->seq)
443             (dp->di_bsddb, &krec, &drec, R_NEXT);
444         if (status == 0) {
445             if (krec.size > sizeof(buf))
446                 data = malloc(krec.size);
447             else data = buf;
448             if (data != NULL)
449                 memcpy(data,krec.data,krec.size);
450         }
451         BSDDB_END_SAVE(dp)
452         if (data == NULL) return PyErr_NoMemory();
453     }
454     if (status < 0) {
455         PyErr_SetFromErrno(BsddbError);
456         Py_DECREF(list);
457         return NULL;
458     }
459     if (dp->di_size < 0)
460         dp->di_size = PyList_Size(list); /* We just did the work */
461     return list;
462 }
463 
464 static PyObject *
bsddb_has_key(bsddbobject * dp,PyObject * args)465 bsddb_has_key(bsddbobject *dp, PyObject *args)
466 {
467     DBT krec, drec;
468     int status;
469     char *data;
470     int size;
471     recno_t recno;
472 
473     if (dp->di_type == DB_RECNO) {
474         if (!PyArg_ParseTuple(args, "i;key type must be integer",
475                               &recno)) {
476             return NULL;
477         }
478         krec.data = &recno;
479         krec.size = sizeof(recno);
480     }
481     else {
482         if (!PyArg_ParseTuple(args, "s#;key type must be string",
483                               &data, &size)) {
484             return NULL;
485         }
486         krec.data = data;
487         krec.size = size;
488     }
489     check_bsddbobject_open(dp, NULL);
490 
491     BSDDB_BGN_SAVE(dp)
492     status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
493     BSDDB_END_SAVE(dp)
494     if (status < 0) {
495         PyErr_SetFromErrno(BsddbError);
496         return NULL;
497     }
498 
499     return PyInt_FromLong(status == 0);
500 }
501 
502 static PyObject *
bsddb_set_location(bsddbobject * dp,PyObject * key)503 bsddb_set_location(bsddbobject *dp, PyObject *key)
504 {
505     int status;
506     DBT krec, drec;
507     char *data = NULL;
508     char buf[4096];
509     int size;
510     PyObject *result;
511     recno_t recno;
512 
513     if (dp->di_type == DB_RECNO) {
514         if (!PyArg_ParseTuple(key, "i;key type must be integer",
515                               &recno)) {
516             return NULL;
517         }
518         krec.data = &recno;
519         krec.size = sizeof(recno);
520     }
521     else {
522         if (!PyArg_ParseTuple(key, "s#;key type must be string",
523                               &data, &size)) {
524             return NULL;
525         }
526         krec.data = data;
527         krec.size = size;
528     }
529     check_bsddbobject_open(dp, NULL);
530 
531     BSDDB_BGN_SAVE(dp)
532     status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
533     if (status == 0) {
534         if (drec.size > sizeof(buf)) data = malloc(drec.size);
535         else data = buf;
536         if (data!=NULL) memcpy(data,drec.data,drec.size);
537     }
538     BSDDB_END_SAVE(dp)
539     if (data==NULL) return PyErr_NoMemory();
540     if (status != 0) {
541         if (status < 0)
542             PyErr_SetFromErrno(BsddbError);
543         else
544             PyErr_SetObject(PyExc_KeyError, key);
545         return NULL;
546     }
547 
548     if (dp->di_type == DB_RECNO)
549         result = Py_BuildValue("is#", *((int*)krec.data),
550                                data, drec.size);
551     else
552         result = Py_BuildValue("s#s#", krec.data, krec.size,
553                                data, drec.size);
554     if (data != buf) free(data);
555     return result;
556 }
557 
558 static PyObject *
bsddb_seq(bsddbobject * dp,int sequence_request)559 bsddb_seq(bsddbobject *dp, int sequence_request)
560 {
561     int status;
562     DBT krec, drec;
563     char *kdata=NULL,kbuf[4096];
564     char *ddata=NULL,dbuf[4096];
565     PyObject *result;
566 
567     check_bsddbobject_open(dp, NULL);
568     krec.data = 0;
569     krec.size = 0;
570 
571     BSDDB_BGN_SAVE(dp)
572     status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec,
573                                  &drec, sequence_request);
574     if (status == 0) {
575         if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
576         else kdata = kbuf;
577         if (kdata != NULL) memcpy(kdata,krec.data,krec.size);
578         if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
579         else ddata = dbuf;
580         if (ddata != NULL) memcpy(ddata,drec.data,drec.size);
581     }
582     BSDDB_END_SAVE(dp)
583     if (status == 0) {
584         if ((kdata == NULL) || (ddata == NULL))
585             return PyErr_NoMemory();
586     }
587     else {
588         /* (status != 0) */
589         if (status < 0)
590             PyErr_SetFromErrno(BsddbError);
591         else
592             PyErr_SetString(PyExc_KeyError, "no key/data pairs");
593         return NULL;
594     }
595 
596     if (dp->di_type == DB_RECNO)
597         result = Py_BuildValue("is#", *((int*)kdata),
598                                ddata, drec.size);
599     else
600         result = Py_BuildValue("s#s#", kdata, krec.size,
601                                ddata, drec.size);
602     if (kdata != kbuf) free(kdata);
603     if (ddata != dbuf) free(ddata);
604     return result;
605 }
606 
607 static PyObject *
bsddb_next(bsddbobject * dp)608 bsddb_next(bsddbobject *dp)
609 {
610     return bsddb_seq(dp, R_NEXT);
611 }
612 static PyObject *
bsddb_previous(bsddbobject * dp)613 bsddb_previous(bsddbobject *dp)
614 {
615     return bsddb_seq(dp, R_PREV);
616 }
617 static PyObject *
bsddb_first(bsddbobject * dp)618 bsddb_first(bsddbobject *dp)
619 {
620     return bsddb_seq(dp, R_FIRST);
621 }
622 static PyObject *
bsddb_last(bsddbobject * dp)623 bsddb_last(bsddbobject *dp)
624 {
625     return bsddb_seq(dp, R_LAST);
626 }
627 static PyObject *
bsddb_sync(bsddbobject * dp)628 bsddb_sync(bsddbobject *dp)
629 {
630     int status;
631 
632     check_bsddbobject_open(dp, NULL);
633     BSDDB_BGN_SAVE(dp)
634     status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
635     BSDDB_END_SAVE(dp)
636     if (status != 0) {
637         PyErr_SetFromErrno(BsddbError);
638         return NULL;
639     }
640     return PyInt_FromLong(0);
641 }
642 static PyMethodDef bsddb_methods[] = {
643     {"close",                   (PyCFunction)bsddb_close, METH_NOARGS},
644     {"keys",                    (PyCFunction)bsddb_keys, METH_NOARGS},
645     {"has_key",                 (PyCFunction)bsddb_has_key, METH_VARARGS},
646     {"set_location",            (PyCFunction)bsddb_set_location, METH_VARARGS},
647     {"next",                    (PyCFunction)bsddb_next, METH_NOARGS},
648     {"previous",        (PyCFunction)bsddb_previous, METH_NOARGS},
649     {"first",                   (PyCFunction)bsddb_first, METH_NOARGS},
650     {"last",                    (PyCFunction)bsddb_last, METH_NOARGS},
651     {"sync",                    (PyCFunction)bsddb_sync, METH_NOARGS},
652     {NULL,              NULL}           /* sentinel */
653 };
654 
655 static PyObject *
bsddb_getattr(PyObject * dp,char * name)656 bsddb_getattr(PyObject *dp, char *name)
657 {
658     return Py_FindMethod(bsddb_methods, dp, name);
659 }
660 
661 static PyTypeObject Bsddbtype = {
662     PyObject_HEAD_INIT(NULL)
663     0,
664     "bsddb.bsddb",
665     sizeof(bsddbobject),
666     0,
667     (destructor)bsddb_dealloc, /*tp_dealloc*/
668     0,                          /*tp_print*/
669     (getattrfunc)bsddb_getattr, /*tp_getattr*/
670     0,                          /*tp_setattr*/
671     0,                          /*tp_compare*/
672     0,                          /*tp_repr*/
673     0,                          /*tp_as_number*/
674     0,                          /*tp_as_sequence*/
675     &bsddb_as_mapping,          /*tp_as_mapping*/
676 };
677 
678 static PyObject *
bsdhashopen(PyObject * self,PyObject * args)679 bsdhashopen(PyObject *self, PyObject *args)
680 {
681     char *file;
682     char *flag = NULL;
683     int flags = O_RDONLY;
684     int mode = 0666;
685     int bsize = 0;
686     int ffactor = 0;
687     int nelem = 0;
688     int cachesize = 0;
689     int hash = 0; /* XXX currently ignored */
690     int lorder = 0;
691 
692     if (!PyArg_ParseTuple(args, "z|siiiiiii:hashopen",
693                           &file, &flag, &mode,
694                           &bsize, &ffactor, &nelem, &cachesize,
695                           &hash, &lorder))
696         return NULL;
697     if (flag != NULL) {
698         /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
699         if (flag[0] == 'r')
700             flags = O_RDONLY;
701         else if (flag[0] == 'w')
702             flags = O_RDWR;
703         else if (flag[0] == 'c')
704             flags = O_RDWR|O_CREAT;
705         else if (flag[0] == 'n')
706             flags = O_RDWR|O_CREAT|O_TRUNC;
707         else {
708             PyErr_SetString(BsddbError,
709                 "Flag should begin with 'r', 'w', 'c' or 'n'");
710             return NULL;
711         }
712         if (flag[1] == 'l') {
713 #if defined(O_EXLOCK) && defined(O_SHLOCK)
714             if (flag[0] == 'r')
715                 flags |= O_SHLOCK;
716             else
717                 flags |= O_EXLOCK;
718 #else
719             PyErr_SetString(BsddbError,
720                          "locking not supported on this platform");
721             return NULL;
722 #endif
723         }
724     }
725     return newdbhashobject(file, flags, mode,
726                            bsize, ffactor, nelem, cachesize, hash, lorder);
727 }
728 
729 static PyObject *
bsdbtopen(PyObject * self,PyObject * args)730 bsdbtopen(PyObject *self, PyObject *args)
731 {
732     char *file;
733     char *flag = NULL;
734     int flags = O_RDONLY;
735     int mode = 0666;
736     int cachesize = 0;
737     int maxkeypage = 0;
738     int minkeypage = 0;
739     int btflags = 0;
740     unsigned int psize = 0;
741     int lorder = 0;
742 
743     if (!PyArg_ParseTuple(args, "z|siiiiiii:btopen",
744                           &file, &flag, &mode,
745                           &btflags, &cachesize, &maxkeypage, &minkeypage,
746                           &psize, &lorder))
747         return NULL;
748     if (flag != NULL) {
749         /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
750         if (flag[0] == 'r')
751             flags = O_RDONLY;
752         else if (flag[0] == 'w')
753             flags = O_RDWR;
754         else if (flag[0] == 'c')
755             flags = O_RDWR|O_CREAT;
756         else if (flag[0] == 'n')
757             flags = O_RDWR|O_CREAT|O_TRUNC;
758         else {
759             PyErr_SetString(BsddbError,
760                    "Flag should begin with 'r', 'w', 'c' or 'n'");
761             return NULL;
762         }
763         if (flag[1] == 'l') {
764 #if defined(O_EXLOCK) && defined(O_SHLOCK)
765             if (flag[0] == 'r')
766                 flags |= O_SHLOCK;
767             else
768                 flags |= O_EXLOCK;
769 #else
770             PyErr_SetString(BsddbError,
771                         "locking not supported on this platform");
772             return NULL;
773 #endif
774         }
775     }
776     return newdbbtobject(file, flags, mode,
777                          btflags, cachesize, maxkeypage, minkeypage,
778                          psize, lorder);
779 }
780 
781 static PyObject *
bsdrnopen(PyObject * self,PyObject * args)782 bsdrnopen(PyObject *self, PyObject *args)
783 {
784     char *file;
785     char *flag = NULL;
786     int flags = O_RDONLY;
787     int mode = 0666;
788     int cachesize = 0;
789     int rnflags = 0;
790     unsigned int psize = 0;
791     int lorder = 0;
792     size_t reclen = 0;
793     char  *bval = "";
794     char *bfname = NULL;
795 
796     if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen",
797                           &file, &flag, &mode,
798                           &rnflags, &cachesize, &psize, &lorder,
799                           &reclen, &bval, &bfname))
800         return NULL;
801 
802     if (flag != NULL) {
803         /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
804         if (flag[0] == 'r')
805             flags = O_RDONLY;
806         else if (flag[0] == 'w')
807             flags = O_RDWR;
808         else if (flag[0] == 'c')
809             flags = O_RDWR|O_CREAT;
810         else if (flag[0] == 'n')
811             flags = O_RDWR|O_CREAT|O_TRUNC;
812         else {
813             PyErr_SetString(BsddbError,
814                    "Flag should begin with 'r', 'w', 'c' or 'n'");
815             return NULL;
816         }
817         if (flag[1] == 'l') {
818 #if defined(O_EXLOCK) && defined(O_SHLOCK)
819             if (flag[0] == 'r')
820                 flags |= O_SHLOCK;
821             else
822                 flags |= O_EXLOCK;
823 #else
824             PyErr_SetString(BsddbError,
825                         "locking not supported on this platform");
826             return NULL;
827 #endif
828         }
829         else if (flag[1] != '\0') {
830             PyErr_SetString(BsddbError,
831                            "Flag char 2 should be 'l' or absent");
832             return NULL;
833         }
834     }
835     return newdbrnobject(file, flags, mode, rnflags, cachesize,
836                          psize, lorder, reclen, bval[0], bfname);
837 }
838 
839 static PyMethodDef bsddbmodule_methods[] = {
840     {"hashopen",        (PyCFunction)bsdhashopen, METH_VARARGS},
841     {"btopen",          (PyCFunction)bsdbtopen, METH_VARARGS},
842     {"rnopen",          (PyCFunction)bsdrnopen, METH_VARARGS},
843     /* strictly for use by dbhhash!!! */
844     {"open",            (PyCFunction)bsdhashopen, METH_VARARGS},
845     {0,                 0},
846 };
847 
848 PyMODINIT_FUNC
initbsddb185(void)849 initbsddb185(void) {
850     PyObject *m, *d;
851 
852     if (PyErr_WarnPy3k("the bsddb185 module has been removed in "
853                        "Python 3.0", 2) < 0)
854         return;
855 
856     Bsddbtype.ob_type = &PyType_Type;
857     m = Py_InitModule("bsddb185", bsddbmodule_methods);
858     if (m == NULL)
859         return;
860     d = PyModule_GetDict(m);
861     BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
862     if (BsddbError != NULL)
863         PyDict_SetItemString(d, "error", BsddbError);
864 }
865