1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "apr_strings.h"
18 #define APR_WANT_MEMFUNC
25 #include <stdlib.h> /* for abort() */
31 #include "apr_dbm_private.h"
34 * We pick up all varieties of Berkeley DB through db.h (included through
35 * apu_select_dbm.h). This code has been compiled/tested against DB1,
36 * DB_185, DB2, DB3, and DB4.
39 #if defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 4)
40 /* We will treat anything greater than 4.1 as DB4.
41 * We can treat 4.0 as DB3.
43 #if defined(DB_VERSION_MINOR) && (DB_VERSION_MINOR >= 1)
48 #elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 3)
50 #elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2)
70 #define GET_BDB(f) (((real_file_t *)(f))->bdb)
72 #define do_fetch(bdb, k, v) ((*(bdb)->get)(bdb, TXN_ARG &(k), &(v), 0))
75 #include <sys/fcntl.h>
76 #define APR_DBM_DBMODE_RO O_RDONLY
77 #define APR_DBM_DBMODE_RW O_RDWR
78 #define APR_DBM_DBMODE_RWCREATE (O_CREAT | O_RDWR)
79 #define APR_DBM_DBMODE_RWTRUNC (O_CREAT | O_RDWR | O_TRUNC)
81 #define APR_DBM_DBMODE_RO DB_RDONLY
82 #define APR_DBM_DBMODE_RW 0
83 #define APR_DBM_DBMODE_RWCREATE DB_CREATE
84 #define APR_DBM_DBMODE_RWTRUNC DB_TRUNCATE
85 #endif /* DBVER == 1 */
87 /* --------------------------------------------------------------------------
92 /* map a DB error to an apr_status_t */
93 static apr_status_t
db2s(int dberr
)
96 /* ### need to fix this */
97 return APR_OS_START_USEERR
+ dberr
;
104 static apr_status_t
set_error(apr_dbm_t
*dbm
, apr_status_t dbm_said
)
106 apr_status_t rv
= APR_SUCCESS
;
108 /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */
110 if (dbm_said
== APR_SUCCESS
) {
115 /* ### need to fix. dberr was tossed in db2s(). */
116 /* ### use db_strerror() */
117 dbm
->errcode
= dbm_said
;
118 #if DB_VER == 1 || DB_VER == 2
121 dbm
->errmsg
= db_strerror(dbm_said
- APR_OS_START_USEERR
);
129 /* --------------------------------------------------------------------------
131 ** DEFINE THE VTABLE FUNCTIONS FOR BERKELEY DB
133 ** ### we may need three sets of these: db1, db2, db3
136 static apr_status_t
vt_db_open(apr_dbm_t
**pdb
, const char *pathname
,
137 apr_int32_t mode
, apr_fileperms_t perm
,
146 case APR_DBM_READONLY
:
147 dbmode
= APR_DBM_DBMODE_RO
;
149 case APR_DBM_READWRITE
:
150 dbmode
= APR_DBM_DBMODE_RW
;
152 case APR_DBM_RWCREATE
:
153 dbmode
= APR_DBM_DBMODE_RWCREATE
;
155 case APR_DBM_RWTRUNC
:
156 dbmode
= APR_DBM_DBMODE_RWTRUNC
;
166 if ((dberr
= db_create(&file
.bdb
, NULL
, 0)) == 0) {
167 if ((dberr
= (*file
.bdb
->open
)(file
.bdb
,
173 apr_posix_perms2mode(perm
))) != 0) {
174 /* close the DB handler */
175 (void) (*file
.bdb
->close
)(file
.bdb
, 0);
180 dberr
= db_open(pathname
, DB_HASH
, dbmode
, apr_posix_perms2mode(perm
),
181 NULL
, NULL
, &file
.bdb
);
184 file
.bdb
= dbopen(pathname
, dbmode
, apr_posix_perms2mode(perm
),
186 if (file
.bdb
== NULL
)
187 return APR_EGENERAL
; /* ### need a better error */
194 /* we have an open database... return it */
195 *pdb
= apr_pcalloc(pool
, sizeof(**pdb
));
197 (*pdb
)->type
= &apr_dbm_type_db
;
198 (*pdb
)->file
= apr_pmemdup(pool
, &file
, sizeof(file
));
200 /* ### register a cleanup to close the DBM? */
205 static void vt_db_close(apr_dbm_t
*dbm
)
207 (*GET_BDB(dbm
->file
)->close
)(GET_BDB(dbm
->file
)
214 static apr_status_t
vt_db_fetch(apr_dbm_t
*dbm
, apr_datum_t key
,
215 apr_datum_t
* pvalue
)
221 ckey
.data
= key
.dptr
;
222 ckey
.size
= key
.dsize
;
224 dberr
= do_fetch(GET_BDB(dbm
->file
), ckey
, rd
);
226 /* "not found" is not an error. return zero'd value. */
234 memset(&rd
, 0, sizeof(rd
));
238 pvalue
->dptr
= rd
.data
;
239 pvalue
->dsize
= rd
.size
;
241 /* store the error info into DBM, and return a status code. Also, note
242 that *pvalue should have been cleared on error. */
243 return set_error(dbm
, db2s(dberr
));
246 static apr_status_t
vt_db_store(apr_dbm_t
*dbm
, apr_datum_t key
,
253 ckey
.data
= key
.dptr
;
254 ckey
.size
= key
.dsize
;
256 cvalue
.data
= value
.dptr
;
257 cvalue
.size
= value
.dsize
;
259 rv
= db2s((*GET_BDB(dbm
->file
)->put
)(GET_BDB(dbm
->file
),
265 /* store any error info into DBM, and return a status code. */
266 return set_error(dbm
, rv
);
269 static apr_status_t
vt_db_del(apr_dbm_t
*dbm
, apr_datum_t key
)
274 ckey
.data
= key
.dptr
;
275 ckey
.size
= key
.dsize
;
277 rv
= db2s((*GET_BDB(dbm
->file
)->del
)(GET_BDB(dbm
->file
),
282 /* store any error info into DBM, and return a status code. */
283 return set_error(dbm
, rv
);
286 static int vt_db_exists(apr_dbm_t
*dbm
, apr_datum_t key
)
288 DBT ckey
= { 0 }; /* converted key */
292 ckey
.data
= key
.dptr
;
293 ckey
.size
= key
.dsize
;
295 dberr
= do_fetch(GET_BDB(dbm
->file
), ckey
, data
);
297 /* note: the result data is "loaned" to us; we don't need to free it */
299 /* DB returns DB_NOTFOUND if it doesn't exist. but we want to say
300 that *any* error means it doesn't exist. */
304 static apr_status_t
vt_db_firstkey(apr_dbm_t
*dbm
, apr_datum_t
* pkey
)
306 real_file_t
*f
= dbm
->file
;
312 dberr
= (*f
->bdb
->seq
)(f
->bdb
, &first
, &data
, R_FIRST
);
314 if ((dberr
= (*f
->bdb
->cursor
)(f
->bdb
, NULL
, &f
->curs
315 #if DB_VER >= 3 || ((DB_VERSION_MAJOR == 2) && (DB_VERSION_MINOR > 5))
319 dberr
= (*f
->curs
->c_get
)(f
->curs
, &first
, &data
, DB_FIRST
);
320 if (dberr
== DB_NOTFOUND
) {
321 memset(&first
, 0, sizeof(first
));
322 (*f
->curs
->c_close
)(f
->curs
);
329 pkey
->dptr
= first
.data
;
330 pkey
->dsize
= first
.size
;
332 /* store any error info into DBM, and return a status code. */
333 return set_error(dbm
, db2s(dberr
));
336 static apr_status_t
vt_db_nextkey(apr_dbm_t
*dbm
, apr_datum_t
* pkey
)
338 real_file_t
*f
= dbm
->file
;
343 ckey
.data
= pkey
->dptr
;
344 ckey
.size
= pkey
->dsize
;
347 dberr
= (*f
->bdb
->seq
)(f
->bdb
, &ckey
, &data
, R_NEXT
);
348 if (dberr
== RET_SPECIAL
) {
357 dberr
= (*f
->curs
->c_get
)(f
->curs
, &ckey
, &data
, DB_NEXT
);
358 if (dberr
== DB_NOTFOUND
) {
359 (*f
->curs
->c_close
)(f
->curs
);
367 pkey
->dptr
= ckey
.data
;
368 pkey
->dsize
= ckey
.size
;
370 /* store any error info into DBM, and return a status code. */
371 /* ### or use db2s(dberr) instead of APR_SUCCESS? */
372 return set_error(dbm
, APR_SUCCESS
);
375 static void vt_db_freedatum(apr_dbm_t
*dbm
, apr_datum_t data
)
380 static void vt_db_usednames(apr_pool_t
*pool
, const char *pathname
,
381 const char **used1
, const char **used2
)
383 *used1
= apr_pstrdup(pool
, pathname
);
388 APU_DECLARE_DATA
const apr_dbm_type_t apr_dbm_type_db
= {
403 #endif /* APU_HAVE_DB */