1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* 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 */