1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include "apu_config.h"
18251876Speter#include "apu.h"
19251876Speter#include "apr_strings.h"
20251876Speter
21251876Speter#if APR_HAVE_STDLIB_H
22251876Speter#include <stdlib.h>     /* for free() */
23251876Speter#endif
24251876Speter
25251876Speter#if APU_HAVE_GDBM
26251876Speter#include "apr_dbm_private.h"
27251876Speter
28251876Speter#include <gdbm.h>
29251876Speter
30251876Speter#define APR_DBM_DBMODE_RO       GDBM_READER
31251876Speter#define APR_DBM_DBMODE_RW       GDBM_WRITER
32251876Speter#define APR_DBM_DBMODE_RWCREATE GDBM_WRCREAT
33251876Speter#define APR_DBM_DBMODE_RWTRUNC  GDBM_NEWDB
34251876Speter
35251876Speter/* map a GDBM error to an apr_status_t */
36251876Speterstatic apr_status_t g2s(int gerr)
37251876Speter{
38251876Speter    if (gerr == -1) {
39251876Speter        /* ### need to fix this */
40251876Speter        return APR_EGENERAL;
41251876Speter    }
42251876Speter
43251876Speter    return APR_SUCCESS;
44251876Speter}
45251876Speter
46251876Speterstatic apr_status_t datum_cleanup(void *dptr)
47251876Speter{
48251876Speter    if (dptr)
49251876Speter        free(dptr);
50251876Speter
51251876Speter    return APR_SUCCESS;
52251876Speter}
53251876Speter
54251876Speterstatic apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said)
55251876Speter{
56251876Speter    apr_status_t rv = APR_SUCCESS;
57251876Speter
58251876Speter    /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */
59251876Speter
60251876Speter    if ((dbm->errcode = gdbm_errno) == GDBM_NO_ERROR) {
61251876Speter        dbm->errmsg = NULL;
62251876Speter    }
63251876Speter    else {
64251876Speter        dbm->errmsg = gdbm_strerror(gdbm_errno);
65251876Speter        rv = APR_EGENERAL;        /* ### need something better */
66251876Speter    }
67251876Speter
68251876Speter    /* captured it. clear it now. */
69251876Speter    gdbm_errno = GDBM_NO_ERROR;
70251876Speter
71251876Speter    return rv;
72251876Speter}
73251876Speter
74251876Speter/* --------------------------------------------------------------------------
75251876Speter**
76251876Speter** DEFINE THE VTABLE FUNCTIONS FOR GDBM
77251876Speter*/
78251876Speter
79251876Speterstatic apr_status_t vt_gdbm_open(apr_dbm_t **pdb, const char *pathname,
80251876Speter                                 apr_int32_t mode, apr_fileperms_t perm,
81251876Speter                                 apr_pool_t *pool)
82251876Speter{
83251876Speter    GDBM_FILE file;
84251876Speter    int dbmode;
85251876Speter
86251876Speter    *pdb = NULL;
87251876Speter
88251876Speter    switch (mode) {
89251876Speter    case APR_DBM_READONLY:
90251876Speter        dbmode = APR_DBM_DBMODE_RO;
91251876Speter        break;
92251876Speter    case APR_DBM_READWRITE:
93251876Speter        dbmode = APR_DBM_DBMODE_RW;
94251876Speter        break;
95251876Speter    case APR_DBM_RWCREATE:
96251876Speter        dbmode = APR_DBM_DBMODE_RWCREATE;
97251876Speter        break;
98251876Speter    case APR_DBM_RWTRUNC:
99251876Speter        dbmode = APR_DBM_DBMODE_RWTRUNC;
100251876Speter        break;
101251876Speter    default:
102251876Speter        return APR_EINVAL;
103251876Speter    }
104251876Speter
105251876Speter    /* Note: stupid cast to get rid of "const" on the pathname */
106251876Speter    file = gdbm_open((char *) pathname, 0, dbmode, apr_posix_perms2mode(perm),
107251876Speter                     NULL);
108251876Speter
109251876Speter    if (file == NULL)
110251876Speter        return APR_EGENERAL;      /* ### need a better error */
111251876Speter
112251876Speter    /* we have an open database... return it */
113251876Speter    *pdb = apr_pcalloc(pool, sizeof(**pdb));
114251876Speter    (*pdb)->pool = pool;
115251876Speter    (*pdb)->type = &apr_dbm_type_gdbm;
116251876Speter    (*pdb)->file = file;
117251876Speter
118251876Speter    /* ### register a cleanup to close the DBM? */
119251876Speter
120251876Speter    return APR_SUCCESS;
121251876Speter}
122251876Speter
123251876Speterstatic void vt_gdbm_close(apr_dbm_t *dbm)
124251876Speter{
125251876Speter    gdbm_close(dbm->file);
126251876Speter}
127251876Speter
128251876Speterstatic apr_status_t vt_gdbm_fetch(apr_dbm_t *dbm, apr_datum_t key,
129251876Speter                                  apr_datum_t *pvalue)
130251876Speter{
131251876Speter    datum kd, rd;
132251876Speter
133251876Speter    kd.dptr = key.dptr;
134251876Speter    kd.dsize = key.dsize;
135251876Speter
136251876Speter    rd = gdbm_fetch(dbm->file, kd);
137251876Speter
138251876Speter    pvalue->dptr = rd.dptr;
139251876Speter    pvalue->dsize = rd.dsize;
140251876Speter
141251876Speter    if (pvalue->dptr)
142251876Speter        apr_pool_cleanup_register(dbm->pool, pvalue->dptr, datum_cleanup,
143251876Speter                                  apr_pool_cleanup_null);
144251876Speter
145251876Speter    /* store the error info into DBM, and return a status code. Also, note
146251876Speter       that *pvalue should have been cleared on error. */
147251876Speter    return set_error(dbm, APR_SUCCESS);
148251876Speter}
149251876Speter
150251876Speterstatic apr_status_t vt_gdbm_store(apr_dbm_t *dbm, apr_datum_t key,
151251876Speter                                  apr_datum_t value)
152251876Speter{
153251876Speter    int rc;
154251876Speter    datum kd, vd;
155251876Speter
156251876Speter    kd.dptr = key.dptr;
157251876Speter    kd.dsize = key.dsize;
158251876Speter
159251876Speter    vd.dptr = value.dptr;
160251876Speter    vd.dsize = value.dsize;
161251876Speter
162251876Speter    rc = gdbm_store(dbm->file, kd, vd, GDBM_REPLACE);
163251876Speter
164251876Speter    /* store any error info into DBM, and return a status code. */
165251876Speter    return set_error(dbm, g2s(rc));
166251876Speter}
167251876Speter
168251876Speterstatic apr_status_t vt_gdbm_del(apr_dbm_t *dbm, apr_datum_t key)
169251876Speter{
170251876Speter    int rc;
171251876Speter    datum kd;
172251876Speter
173251876Speter    kd.dptr = key.dptr;
174251876Speter    kd.dsize = key.dsize;
175251876Speter
176251876Speter    rc = gdbm_delete(dbm->file, kd);
177251876Speter
178251876Speter    /* store any error info into DBM, and return a status code. */
179251876Speter    return set_error(dbm, g2s(rc));
180251876Speter}
181251876Speter
182251876Speterstatic int vt_gdbm_exists(apr_dbm_t *dbm, apr_datum_t key)
183251876Speter{
184251876Speter    datum kd;
185251876Speter
186251876Speter    kd.dptr = key.dptr;
187251876Speter    kd.dsize = key.dsize;
188251876Speter
189251876Speter    return gdbm_exists(dbm->file, kd) != 0;
190251876Speter}
191251876Speter
192251876Speterstatic apr_status_t vt_gdbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey)
193251876Speter{
194251876Speter    datum rd;
195251876Speter
196251876Speter    rd = gdbm_firstkey(dbm->file);
197251876Speter
198251876Speter    pkey->dptr = rd.dptr;
199251876Speter    pkey->dsize = rd.dsize;
200251876Speter
201251876Speter    if (pkey->dptr)
202251876Speter        apr_pool_cleanup_register(dbm->pool, pkey->dptr, datum_cleanup,
203251876Speter                                  apr_pool_cleanup_null);
204251876Speter
205251876Speter    /* store any error info into DBM, and return a status code. */
206251876Speter    return set_error(dbm, APR_SUCCESS);
207251876Speter}
208251876Speter
209251876Speterstatic apr_status_t vt_gdbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey)
210251876Speter{
211251876Speter    datum kd, rd;
212251876Speter
213251876Speter    kd.dptr = pkey->dptr;
214251876Speter    kd.dsize = pkey->dsize;
215251876Speter
216251876Speter    rd = gdbm_nextkey(dbm->file, kd);
217251876Speter
218251876Speter    pkey->dptr = rd.dptr;
219251876Speter    pkey->dsize = rd.dsize;
220251876Speter
221251876Speter    if (pkey->dptr)
222251876Speter        apr_pool_cleanup_register(dbm->pool, pkey->dptr, datum_cleanup,
223251876Speter                                  apr_pool_cleanup_null);
224251876Speter
225251876Speter    /* store any error info into DBM, and return a status code. */
226251876Speter    return set_error(dbm, APR_SUCCESS);
227251876Speter}
228251876Speter
229251876Speterstatic void vt_gdbm_freedatum(apr_dbm_t *dbm, apr_datum_t data)
230251876Speter{
231251876Speter    (void) apr_pool_cleanup_run(dbm->pool, data.dptr, datum_cleanup);
232251876Speter}
233251876Speter
234251876Speterstatic void vt_gdbm_usednames(apr_pool_t *pool, const char *pathname,
235251876Speter                              const char **used1, const char **used2)
236251876Speter{
237251876Speter    *used1 = apr_pstrdup(pool, pathname);
238251876Speter    *used2 = NULL;
239251876Speter}
240251876Speter
241251876SpeterAPU_MODULE_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_gdbm = {
242251876Speter    "gdbm",
243251876Speter    vt_gdbm_open,
244251876Speter    vt_gdbm_close,
245251876Speter    vt_gdbm_fetch,
246251876Speter    vt_gdbm_store,
247251876Speter    vt_gdbm_del,
248251876Speter    vt_gdbm_exists,
249251876Speter    vt_gdbm_firstkey,
250251876Speter    vt_gdbm_nextkey,
251251876Speter    vt_gdbm_freedatum,
252251876Speter    vt_gdbm_usednames
253251876Speter};
254251876Speter
255251876Speter#endif /* APU_HAVE_GDBM */
256