summaryrefslogtreecommitdiff
path: root/ext/DB_File/DB_File.xs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/DB_File/DB_File.xs')
-rw-r--r--ext/DB_File/DB_File.xs119
1 files changed, 107 insertions, 12 deletions
diff --git a/ext/DB_File/DB_File.xs b/ext/DB_File/DB_File.xs
index 489ba96890..fba8dede79 100644
--- a/ext/DB_File/DB_File.xs
+++ b/ext/DB_File/DB_File.xs
@@ -3,8 +3,8 @@
DB_File.xs -- Perl 5 interface to Berkeley DB
written by Paul Marquess <Paul.Marquess@btinternet.com>
- last modified 1st March 2002
- version 1.803
+ last modified 1st September 2002
+ version 1.805
All comments/suggestions/problems are welcome
@@ -101,6 +101,10 @@
1.802 - No change to DB_File.xs
1.803 - FETCH, STORE & DELETE don't map the flags parameter
into the equivalent Berkeley DB function anymore.
+ 1.804 - no change.
+ 1.805 - recursion detection added to the callbacks
+ Support for 4.1.X added.
+ Filter code can now cope with read-only $_
*/
@@ -182,6 +186,10 @@
# define AT_LEAST_DB_3_2
#endif
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+# define AT_LEAST_DB_4_1
+#endif
+
/* map version 2 features & constants onto their version 1 equivalent */
#ifdef DB_Prefix_t
@@ -334,8 +342,8 @@ typedef union INFO {
#define db_get(db, key, value, flags) ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
#ifdef DB_VERSION_MAJOR
-#define db_DESTROY(db) ( db->cursor->c_close(db->cursor),\
- (db->dbp->close)(db->dbp, 0) )
+#define db_DESTROY(db) (!db->aborted && ( db->cursor->c_close(db->cursor),\
+ (db->dbp->close)(db->dbp, 0) ))
#define db_close(db) ((db->dbp)->close)(db->dbp, 0)
#define db_del(db, key, flags) (flagSet(flags, R_CURSOR) \
? ((db->cursor)->c_del)(db->cursor, 0) \
@@ -343,7 +351,7 @@ typedef union INFO {
#else /* ! DB_VERSION_MAJOR */
-#define db_DESTROY(db) ((db->dbp)->close)(db->dbp)
+#define db_DESTROY(db) (!db->aborted && ((db->dbp)->close)(db->dbp))
#define db_close(db) ((db->dbp)->close)(db->dbp)
#define db_del(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
#define db_put(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
@@ -357,8 +365,12 @@ typedef struct {
DBTYPE type ;
DB * dbp ;
SV * compare ;
+ bool in_compare ;
SV * prefix ;
+ bool in_prefix ;
SV * hash ;
+ bool in_hash ;
+ bool aborted ;
int in_memory ;
#ifdef BERKELEY_DB_1_OR_2
INFO info ;
@@ -382,6 +394,8 @@ typedef DBT DBTKEY ;
#define OutputValue(arg, name) \
{ if (RETVAL == 0) { \
my_sv_setpvn(arg, name.data, name.size) ; \
+ TAINT; \
+ SvTAINTED_on(arg); \
DBM_ckFilter(arg, filter_fetch_value,"filter_fetch_value") ; \
} \
}
@@ -394,6 +408,8 @@ typedef DBT DBTKEY ;
} \
else \
sv_setiv(arg, (I32)*(I32*)name.data - 1); \
+ TAINT; \
+ SvTAINTED_on(arg); \
DBM_ckFilter(arg, filter_fetch_key,"filter_fetch_key") ; \
} \
}
@@ -422,6 +438,8 @@ START_MY_CXT
#define CurrentDB (MY_CXT.x_CurrentDB)
#define empty (MY_CXT.x_empty)
+#define ERR_BUFF "DB_File::Error"
+
#ifdef DB_VERSION_MAJOR
static int
@@ -484,6 +502,13 @@ u_int flags ;
#endif /* DB_VERSION_MAJOR */
+static void
+tidyUp(DB_File db)
+{
+ /* db_DESTROY(db); */
+ db->aborted = TRUE ;
+}
+
static int
#ifdef AT_LEAST_DB_3_2
@@ -518,7 +543,14 @@ const DBT * key2 ;
void * data1, * data2 ;
int retval ;
int count ;
+ DB_File keep_CurrentDB = CurrentDB;
+
+ if (CurrentDB->in_compare) {
+ tidyUp(CurrentDB);
+ croak ("DB_File btree_compare: recursion detected\n") ;
+ }
+
data1 = (char *) key1->data ;
data2 = (char *) key2->data ;
@@ -542,18 +574,26 @@ const DBT * key2 ;
PUSHs(sv_2mortal(newSVpvn(data2,key2->size)));
PUTBACK ;
+ CurrentDB->in_compare = TRUE;
+
count = perl_call_sv(CurrentDB->compare, G_SCALAR);
+ CurrentDB = keep_CurrentDB;
+ CurrentDB->in_compare = FALSE;
+
SPAGAIN ;
- if (count != 1)
+ if (count != 1){
+ tidyUp(CurrentDB);
croak ("DB_File btree_compare: expected 1 return value from compare sub, got %d\n", count) ;
+ }
retval = POPi ;
PUTBACK ;
FREETMPS ;
LEAVE ;
+
return (retval) ;
}
@@ -590,7 +630,13 @@ const DBT * key2 ;
char * data1, * data2 ;
int retval ;
int count ;
+ DB_File keep_CurrentDB = CurrentDB;
+ if (CurrentDB->in_prefix){
+ tidyUp(CurrentDB);
+ croak ("DB_File btree_prefix: recursion detected\n") ;
+ }
+
data1 = (char *) key1->data ;
data2 = (char *) key2->data ;
@@ -614,12 +660,19 @@ const DBT * key2 ;
PUSHs(sv_2mortal(newSVpvn(data2,key2->size)));
PUTBACK ;
+ CurrentDB->in_prefix = TRUE;
+
count = perl_call_sv(CurrentDB->prefix, G_SCALAR);
+ CurrentDB = keep_CurrentDB;
+ CurrentDB->in_prefix = FALSE;
+
SPAGAIN ;
- if (count != 1)
+ if (count != 1){
+ tidyUp(CurrentDB);
croak ("DB_File btree_prefix: expected 1 return value from prefix sub, got %d\n", count) ;
+ }
retval = POPi ;
@@ -668,6 +721,12 @@ HASH_CB_SIZE_TYPE size ;
dMY_CXT;
int retval ;
int count ;
+ DB_File keep_CurrentDB = CurrentDB;
+
+ if (CurrentDB->in_hash){
+ tidyUp(CurrentDB);
+ croak ("DB_File hash callback: recursion detected\n") ;
+ }
#ifndef newSVpvn
if (size == 0)
@@ -683,12 +742,19 @@ HASH_CB_SIZE_TYPE size ;
XPUSHs(sv_2mortal(newSVpvn((char*)data,size)));
PUTBACK ;
+ keep_CurrentDB->in_hash = TRUE;
+
count = perl_call_sv(CurrentDB->hash, G_SCALAR);
+ CurrentDB = keep_CurrentDB;
+ CurrentDB->in_hash = FALSE;
+
SPAGAIN ;
- if (count != 1)
+ if (count != 1){
+ tidyUp(CurrentDB);
croak ("DB_File hash_cb: expected 1 return value from hash sub, got %d\n", count) ;
+ }
retval = POPi ;
@@ -699,6 +765,23 @@ HASH_CB_SIZE_TYPE size ;
return (retval) ;
}
+static void
+#ifdef CAN_PROTOTYPE
+db_errcall_cb(const char * db_errpfx, char * buffer)
+#else
+db_errcall_cb(db_errpfx, buffer)
+const char * db_errpfx;
+char * buffer;
+#endif
+{
+ SV * sv = perl_get_sv(ERR_BUFF, FALSE) ;
+ if (sv) {
+ if (db_errpfx)
+ sv_setpvf(sv, "%s: %s", db_errpfx, buffer) ;
+ else
+ sv_setpv(sv, buffer) ;
+ }
+}
#if defined(TRACE) && defined(BERKELEY_DB_1_OR_2)
@@ -808,8 +891,10 @@ I32 value ;
I32 length = GetArrayLength(aTHX_ db) ;
/* check for attempt to write before start of array */
- if (length + value + 1 <= 0)
+ if (length + value + 1 <= 0) {
+ tidyUp(db);
croak("Modification of non-creatable array value attempted, subscript %ld", (long)value) ;
+ }
value = length + value + 1 ;
}
@@ -1333,14 +1418,22 @@ SV * sv ;
Flags |= DB_TRUNCATE ;
#endif
+#ifdef AT_LEAST_DB_4_1
+ status = (RETVAL->dbp->open)(RETVAL->dbp, NULL, name, NULL, RETVAL->type,
+ Flags, mode) ;
+#else
status = (RETVAL->dbp->open)(RETVAL->dbp, name, NULL, RETVAL->type,
Flags, mode) ;
+#endif
/* printf("open returned %d %s\n", status, db_strerror(status)) ; */
- if (status == 0)
+ if (status == 0) {
+ RETVAL->dbp->set_errcall(RETVAL->dbp, db_errcall_cb) ;
+
status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor,
0) ;
- /* printf("cursor returned %d %s\n", status, db_strerror(status)) ; */
+ /* printf("cursor returned %d %s\n", status, db_strerror(status)) ; */
+ }
if (status)
RETVAL->dbp = NULL ;
@@ -1362,6 +1455,7 @@ INCLUDE: constants.xs
BOOT:
{
+ SV * sv_err = perl_get_sv(ERR_BUFF, GV_ADD|GV_ADDMULTI) ;
MY_CXT_INIT;
__getBerkeleyDBInfo() ;
@@ -1404,7 +1498,9 @@ db_DESTROY(db)
dMY_CXT;
INIT:
CurrentDB = db ;
+ Trace(("DESTROY %p\n", db));
CLEANUP:
+ Trace(("DESTROY %p done\n", db));
if (db->hash)
SvREFCNT_dec(db->hash) ;
if (db->compare)
@@ -1468,7 +1564,6 @@ db_FETCH(db, key, flags=0)
DBT_clear(value) ;
CurrentDB = db ;
- /* RETVAL = ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) ; */
RETVAL = db_get(db, key, value, flags) ;
ST(0) = sv_newmortal();
OutputValue(ST(0), value)