Apache HTTPD
apr_dbm_berkeleydb.c
Go to the documentation of this file.
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "apr_strings.h"
18#define APR_WANT_MEMFUNC
19#include "apr_want.h"
20
21#define APU_WANT_DB
22#include "apu_want.h"
23
24#if APR_HAVE_STDLIB_H
25#include <stdlib.h> /* for abort() */
26#endif
27
28#include "apu_config.h"
29#include "apu.h"
30
31#if APU_HAVE_DB
32#include "apr_dbm_private.h"
33
34/*
35 * We pick up all varieties of Berkeley DB through db.h (included through
36 * apu_select_dbm.h). This code has been compiled/tested against DB1,
37 * DB_185, DB2, DB3, and DB4.
38 */
39
40#if defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR >= 4)
41/* We will treat anything greater than 4.1 as DB4.
42 * We can treat 4.0 as DB3.
43 */
44#if DB_VERSION_MAJOR > 4 || (defined(DB_VERSION_MINOR) && (DB_VERSION_MINOR >= 1))
45#define DB_VER 4
46#elif DB_VERSION_MAJOR == 4
47#define DB_VER 3
48#endif
49#elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 3)
50#define DB_VER 3
51#elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2)
52#define DB_VER 2
53#else
54#define DB_VER 1
55#endif
56
57typedef struct {
58 DB *bdb;
59#if DB_VER != 1
60 DBC *curs;
61#endif
63
64
65#if DB_VER == 1
66#define TXN_ARG
67#else
68#define TXN_ARG NULL,
69#endif
70
71#define GET_BDB(f) (((real_file_t *)(f))->bdb)
72
73#define do_fetch(bdb, k, v) ((*(bdb)->get)(bdb, TXN_ARG &(k), &(v), 0))
74
75#if DB_VER == 1
76#include <sys/fcntl.h>
77#define APR_DBM_DBMODE_RO O_RDONLY
78#define APR_DBM_DBMODE_RW O_RDWR
79#define APR_DBM_DBMODE_RWCREATE (O_CREAT | O_RDWR)
80#define APR_DBM_DBMODE_RWTRUNC (O_CREAT | O_RDWR | O_TRUNC)
81#else
82#define APR_DBM_DBMODE_RO DB_RDONLY
83#define APR_DBM_DBMODE_RW 0
84#define APR_DBM_DBMODE_RWCREATE DB_CREATE
85#define APR_DBM_DBMODE_RWTRUNC DB_TRUNCATE
86#endif /* DBVER == 1 */
87
88/* --------------------------------------------------------------------------
89**
90** UTILITY FUNCTIONS
91*/
92
93/* map a DB error to an apr_status_t */
94static apr_status_t db2s(int dberr)
95{
96 if (dberr != 0) {
97 /* ### need to fix this */
99 }
100
101 return APR_SUCCESS;
102}
103
104
106{
108
109 /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */
110
111 if (dbm_said == APR_SUCCESS) {
112 dbm->errcode = 0;
113 dbm->errmsg = NULL;
114 }
115 else {
116 /* ### need to fix. dberr was tossed in db2s(). */
117 /* ### use db_strerror() */
118 dbm->errcode = dbm_said;
119#if DB_VER == 1 || DB_VER == 2
120 dbm->errmsg = NULL;
121#else
123#endif
124 rv = dbm_said;
125 }
126
127 return rv;
128}
129
130/* --------------------------------------------------------------------------
131**
132** DEFINE THE VTABLE FUNCTIONS FOR BERKELEY DB
133**
134** ### we may need three sets of these: db1, db2, db3
135*/
136
137static apr_status_t vt_db_open(apr_dbm_t **pdb, const char *pathname,
140{
142 int dbmode;
143
144 *pdb = NULL;
145
146 switch (mode) {
147 case APR_DBM_READONLY:
149 break;
152 break;
153 case APR_DBM_RWCREATE:
155 break;
156 case APR_DBM_RWTRUNC:
158 break;
159 default:
160 return APR_EINVAL;
161 }
162
163 {
164 int dberr;
165
166#if DB_VER >= 3
167 if ((dberr = db_create(&file.bdb, NULL, 0)) == 0) {
168 if ((dberr = (*file.bdb->open)(file.bdb,
169#if DB_VER == 4
170 NULL,
171#endif
172 pathname, NULL,
173 DB_HASH, dbmode,
174 apr_posix_perms2mode(perm))) != 0) {
175 /* close the DB handler */
176 (void) (*file.bdb->close)(file.bdb, 0);
177 }
178 }
179 file.curs = NULL;
180#elif DB_VER == 2
182 NULL, NULL, &file.bdb);
183 file.curs = NULL;
184#else
186 DB_HASH, NULL);
187 if (file.bdb == NULL)
188 return APR_EGENERAL; /* ### need a better error */
189 dberr = 0;
190#endif
191 if (dberr != 0)
192 return db2s(dberr);
193 }
194
195 /* we have an open database... return it */
196 *pdb = apr_pcalloc(pool, sizeof(**pdb));
197 (*pdb)->pool = pool;
198 (*pdb)->type = &apr_dbm_type_db;
199 (*pdb)->file = apr_pmemdup(pool, &file, sizeof(file));
200
201 /* ### register a cleanup to close the DBM? */
202
203 return APR_SUCCESS;
204}
205
206static void vt_db_close(apr_dbm_t *dbm)
207{
208 (*GET_BDB(dbm->file)->close)(GET_BDB(dbm->file)
209#if DB_VER != 1
210 , 0
211#endif
212 );
213}
214
217{
218 DBT ckey = { 0 };
219 DBT rd = { 0 };
220 int dberr;
221
222 ckey.data = key.dptr;
223 ckey.size = key.dsize;
224
225 dberr = do_fetch(GET_BDB(dbm->file), ckey, rd);
226
227 /* "not found" is not an error. return zero'd value. */
228 if (dberr ==
229#if DB_VER == 1
231#else
233#endif
234 ) {
235 memset(&rd, 0, sizeof(rd));
236 dberr = 0;
237 }
238
239 pvalue->dptr = rd.data;
240 pvalue->dsize = rd.size;
241
242 /* store the error info into DBM, and return a status code. Also, note
243 that *pvalue should have been cleared on error. */
244 return set_error(dbm, db2s(dberr));
245}
246
249{
250 apr_status_t rv;
251 DBT ckey = { 0 };
252 DBT cvalue = { 0 };
253
254 ckey.data = key.dptr;
255 ckey.size = key.dsize;
256
257 cvalue.data = value.dptr;
258 cvalue.size = value.dsize;
259
260 rv = db2s((*GET_BDB(dbm->file)->put)(GET_BDB(dbm->file),
261 TXN_ARG
262 &ckey,
263 &cvalue,
264 0));
265
266 /* store any error info into DBM, and return a status code. */
267 return set_error(dbm, rv);
268}
269
271{
272 apr_status_t rv;
273 DBT ckey = { 0 };
274
275 ckey.data = key.dptr;
276 ckey.size = key.dsize;
277
278 rv = db2s((*GET_BDB(dbm->file)->del)(GET_BDB(dbm->file),
279 TXN_ARG
280 &ckey,
281 0));
282
283 /* store any error info into DBM, and return a status code. */
284 return set_error(dbm, rv);
285}
286
288{
289 DBT ckey = { 0 }; /* converted key */
290 DBT data = { 0 };
291 int dberr;
292
293 ckey.data = key.dptr;
294 ckey.size = key.dsize;
295
296 dberr = do_fetch(GET_BDB(dbm->file), ckey, data);
297
298 /* note: the result data is "loaned" to us; we don't need to free it */
299
300 /* DB returns DB_NOTFOUND if it doesn't exist. but we want to say
301 that *any* error means it doesn't exist. */
302 return dberr == 0;
303}
304
306{
307 real_file_t *f = dbm->file;
308 DBT first = { 0 };
309 DBT data = { 0 };
310 int dberr;
311
312#if DB_VER == 1
313 dberr = (*f->bdb->seq)(f->bdb, &first, &data, R_FIRST);
314#else
315 if ((dberr = (*f->bdb->cursor)(f->bdb, NULL, &f->curs
316#if DB_VER >= 3 || ((DB_VERSION_MAJOR == 2) && (DB_VERSION_MINOR > 5))
317 , 0
318#endif
319 )) == 0) {
320 dberr = (*f->curs->c_get)(f->curs, &first, &data, DB_FIRST);
321 if (dberr == DB_NOTFOUND) {
322 memset(&first, 0, sizeof(first));
323 (*f->curs->c_close)(f->curs);
324 f->curs = NULL;
325 dberr = 0;
326 }
327 }
328#endif
329
330 pkey->dptr = first.data;
331 pkey->dsize = first.size;
332
333 /* store any error info into DBM, and return a status code. */
334 return set_error(dbm, db2s(dberr));
335}
336
338{
339 real_file_t *f = dbm->file;
340 DBT ckey = { 0 };
341 DBT data = { 0 };
342 int dberr;
343
344 ckey.data = pkey->dptr;
345 ckey.size = pkey->dsize;
346
347#if DB_VER == 1
348 dberr = (*f->bdb->seq)(f->bdb, &ckey, &data, R_NEXT);
349 if (dberr == RET_SPECIAL) {
350 dberr = 0;
351 ckey.data = NULL;
352 ckey.size = 0;
353 }
354#else
355 if (f->curs == NULL)
356 return APR_EINVAL;
357
358 dberr = (*f->curs->c_get)(f->curs, &ckey, &data, DB_NEXT);
359 if (dberr == DB_NOTFOUND) {
360 (*f->curs->c_close)(f->curs);
361 f->curs = NULL;
362 dberr = 0;
363 ckey.data = NULL;
364 ckey.size = 0;
365 }
366#endif
367
368 pkey->dptr = ckey.data;
369 pkey->dsize = ckey.size;
370
371 /* store any error info into DBM, and return a status code. */
372 /* ### or use db2s(dberr) instead of APR_SUCCESS? */
373 return set_error(dbm, APR_SUCCESS);
374}
375
377{
378 /* nothing to do */
379}
380
381static void vt_db_usednames(apr_pool_t *pool, const char *pathname,
382 const char **used1, const char **used2)
383{
385 *used2 = NULL;
386}
387
388
390 "db",
391
396 vt_db_del,
402};
403
404#endif /* APU_HAVE_DB */
APU_MODULE_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_db
APR Strings library.
APR Standard Headers Support.
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_EINVAL
Definition apr_errno.h:711
apr_file_t * f
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
apr_datum_t * pkey
Definition apr_dbm.h:158
apr_datum_t apr_datum_t * pvalue
Definition apr_dbm.h:128
#define APR_DBM_RWTRUNC
Definition apr_dbm.h:59
#define APR_DBM_RWCREATE
Definition apr_dbm.h:58
#define APR_DBM_READONLY
Definition apr_dbm.h:56
const char const char const char const char ** used2
Definition apr_dbm.h:203
const char const char const char ** used1
Definition apr_dbm.h:202
#define APR_DBM_READWRITE
Definition apr_dbm.h:57
const char const char * pathname
Definition apr_dbm.h:201
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
const char * value
Definition apr_env.h:51
#define APR_OS_START_USEERR
Definition apr_errno.h:169
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_int32_t apr_fileperms_t
const char * key
void * data
const char apr_file_t * file
const char apr_int32_t apr_fileperms_t perm
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const apr_array_header_t * first
Definition apr_tables.h:207
return NULL
Definition mod_so.c:359
apr_size_t dsize
Definition apr_dbm.h:52
char * dptr
Definition apr_dbm.h:50