]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr-util/dbm/apr_dbm_gdbm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr-util / dbm / apr_dbm_gdbm.c
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 "apu_config.h"
18 #include "apu.h"
19 #include "apr_strings.h"
20
21 #if APR_HAVE_STDLIB_H
22 #include <stdlib.h>     /* for free() */
23 #endif
24
25 #if APU_HAVE_GDBM
26 #include "apr_dbm_private.h"
27
28 #include <gdbm.h>
29
30 #define APR_DBM_DBMODE_RO       GDBM_READER
31 #define APR_DBM_DBMODE_RW       GDBM_WRITER
32 #define APR_DBM_DBMODE_RWCREATE GDBM_WRCREAT
33 #define APR_DBM_DBMODE_RWTRUNC  GDBM_NEWDB
34
35 /* map a GDBM error to an apr_status_t */
36 static apr_status_t g2s(int gerr)
37 {
38     if (gerr == -1) {
39         /* ### need to fix this */
40         return APR_EGENERAL;
41     }
42
43     return APR_SUCCESS;
44 }
45
46 static apr_status_t datum_cleanup(void *dptr)
47 {
48     if (dptr)
49         free(dptr);
50
51     return APR_SUCCESS;
52 }
53
54 static apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said)
55 {
56     apr_status_t rv = APR_SUCCESS;
57
58     /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */
59
60     if ((dbm->errcode = gdbm_errno) == GDBM_NO_ERROR) {
61         dbm->errmsg = NULL;
62     }
63     else {
64         dbm->errmsg = gdbm_strerror(gdbm_errno);
65         rv = APR_EGENERAL;        /* ### need something better */
66     }
67
68     /* captured it. clear it now. */
69     gdbm_errno = GDBM_NO_ERROR;
70
71     return rv;
72 }
73
74 /* --------------------------------------------------------------------------
75 **
76 ** DEFINE THE VTABLE FUNCTIONS FOR GDBM
77 */
78
79 static apr_status_t vt_gdbm_open(apr_dbm_t **pdb, const char *pathname,
80                                  apr_int32_t mode, apr_fileperms_t perm,
81                                  apr_pool_t *pool)
82 {
83     GDBM_FILE file;
84     int dbmode;
85
86     *pdb = NULL;
87
88     switch (mode) {
89     case APR_DBM_READONLY:
90         dbmode = APR_DBM_DBMODE_RO;
91         break;
92     case APR_DBM_READWRITE:
93         dbmode = APR_DBM_DBMODE_RW;
94         break;
95     case APR_DBM_RWCREATE:
96         dbmode = APR_DBM_DBMODE_RWCREATE;
97         break;
98     case APR_DBM_RWTRUNC:
99         dbmode = APR_DBM_DBMODE_RWTRUNC;
100         break;
101     default:
102         return APR_EINVAL;
103     }
104
105     /* Note: stupid cast to get rid of "const" on the pathname */
106     file = gdbm_open((char *) pathname, 0, dbmode, apr_posix_perms2mode(perm),
107                      NULL);
108
109     if (file == NULL)
110         return APR_EGENERAL;      /* ### need a better error */
111
112     /* we have an open database... return it */
113     *pdb = apr_pcalloc(pool, sizeof(**pdb));
114     (*pdb)->pool = pool;
115     (*pdb)->type = &apr_dbm_type_gdbm;
116     (*pdb)->file = file;
117
118     /* ### register a cleanup to close the DBM? */
119
120     return APR_SUCCESS;
121 }
122
123 static void vt_gdbm_close(apr_dbm_t *dbm)
124 {
125     gdbm_close(dbm->file);
126 }
127
128 static apr_status_t vt_gdbm_fetch(apr_dbm_t *dbm, apr_datum_t key,
129                                   apr_datum_t *pvalue)
130 {
131     datum kd, rd;
132
133     kd.dptr = key.dptr;
134     kd.dsize = key.dsize;
135
136     rd = gdbm_fetch(dbm->file, kd);
137
138     pvalue->dptr = rd.dptr;
139     pvalue->dsize = rd.dsize;
140
141     if (pvalue->dptr)
142         apr_pool_cleanup_register(dbm->pool, pvalue->dptr, datum_cleanup,
143                                   apr_pool_cleanup_null);
144
145     /* store the error info into DBM, and return a status code. Also, note
146        that *pvalue should have been cleared on error. */
147     return set_error(dbm, APR_SUCCESS);
148 }
149
150 static apr_status_t vt_gdbm_store(apr_dbm_t *dbm, apr_datum_t key,
151                                   apr_datum_t value)
152 {
153     int rc;
154     datum kd, vd;
155
156     kd.dptr = key.dptr;
157     kd.dsize = key.dsize;
158
159     vd.dptr = value.dptr;
160     vd.dsize = value.dsize;
161
162     rc = gdbm_store(dbm->file, kd, vd, GDBM_REPLACE);
163
164     /* store any error info into DBM, and return a status code. */
165     return set_error(dbm, g2s(rc));
166 }
167
168 static apr_status_t vt_gdbm_del(apr_dbm_t *dbm, apr_datum_t key)
169 {
170     int rc;
171     datum kd;
172
173     kd.dptr = key.dptr;
174     kd.dsize = key.dsize;
175
176     rc = gdbm_delete(dbm->file, kd);
177
178     /* store any error info into DBM, and return a status code. */
179     return set_error(dbm, g2s(rc));
180 }
181
182 static int vt_gdbm_exists(apr_dbm_t *dbm, apr_datum_t key)
183 {
184     datum kd;
185
186     kd.dptr = key.dptr;
187     kd.dsize = key.dsize;
188
189     return gdbm_exists(dbm->file, kd) != 0;
190 }
191
192 static apr_status_t vt_gdbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey)
193 {
194     datum rd;
195
196     rd = gdbm_firstkey(dbm->file);
197
198     pkey->dptr = rd.dptr;
199     pkey->dsize = rd.dsize;
200
201     if (pkey->dptr)
202         apr_pool_cleanup_register(dbm->pool, pkey->dptr, datum_cleanup,
203                                   apr_pool_cleanup_null);
204
205     /* store any error info into DBM, and return a status code. */
206     return set_error(dbm, APR_SUCCESS);
207 }
208
209 static apr_status_t vt_gdbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey)
210 {
211     datum kd, rd;
212
213     kd.dptr = pkey->dptr;
214     kd.dsize = pkey->dsize;
215
216     rd = gdbm_nextkey(dbm->file, kd);
217
218     pkey->dptr = rd.dptr;
219     pkey->dsize = rd.dsize;
220
221     if (pkey->dptr)
222         apr_pool_cleanup_register(dbm->pool, pkey->dptr, datum_cleanup,
223                                   apr_pool_cleanup_null);
224
225     /* store any error info into DBM, and return a status code. */
226     return set_error(dbm, APR_SUCCESS);
227 }
228
229 static void vt_gdbm_freedatum(apr_dbm_t *dbm, apr_datum_t data)
230 {
231     (void) apr_pool_cleanup_run(dbm->pool, data.dptr, datum_cleanup);
232 }
233
234 static void vt_gdbm_usednames(apr_pool_t *pool, const char *pathname,
235                               const char **used1, const char **used2)
236 {
237     *used1 = apr_pstrdup(pool, pathname);
238     *used2 = NULL;
239 }
240
241 APU_MODULE_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_gdbm = {
242     "gdbm",
243     vt_gdbm_open,
244     vt_gdbm_close,
245     vt_gdbm_fetch,
246     vt_gdbm_store,
247     vt_gdbm_del,
248     vt_gdbm_exists,
249     vt_gdbm_firstkey,
250     vt_gdbm_nextkey,
251     vt_gdbm_freedatum,
252     vt_gdbm_usednames
253 };
254
255 #endif /* APU_HAVE_GDBM */