]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/apr-util/dbm/apr_dbm.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / apr-util / dbm / apr_dbm.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 "apr.h"
18 #include "apr_dso.h"
19 #include "apr_hash.h"
20 #include "apr_errno.h"
21 #include "apr_pools.h"
22 #include "apr_strings.h"
23 #define APR_WANT_MEMFUNC
24 #define APR_WANT_STRFUNC
25 #include "apr_want.h"
26 #include "apr_general.h"
27 #include "apr_atomic.h"
28
29 #include "apu_config.h"
30 #include "apu.h"
31 #include "apu_internal.h"
32 #include "apu_version.h"
33 #include "apr_dbm_private.h"
34 #include "apu_select_dbm.h"
35 #include "apr_dbm.h"
36 #include "apr_dbm_private.h"
37
38 /* ### note: the setting of DBM_VTABLE will go away once we have multiple
39    ### DBMs in here. 
40    ### Well, that day is here.  So, do we remove DBM_VTABLE and the old
41    ### API entirely?  Oh, what to do.  We need an APU_DEFAULT_DBM #define.
42    ### Sounds like a job for autoconf. */
43
44 #if APU_USE_DB
45 #define DBM_VTABLE apr_dbm_type_db
46 #define DBM_NAME   "db"
47 #elif APU_USE_GDBM
48 #define DBM_VTABLE apr_dbm_type_gdbm
49 #define DBM_NAME   "gdbm"
50 #elif APU_USE_NDBM
51 #define DBM_VTABLE apr_dbm_type_ndbm
52 #define DBM_NAME   "ndbm"
53 #elif APU_USE_SDBM
54 #define DBM_VTABLE apr_dbm_type_sdbm
55 #define DBM_NAME   "sdbm"
56 #else /* Not in the USE_xDBM list above */
57 #error a DBM implementation was not specified
58 #endif
59
60 #if APU_DSO_BUILD
61
62 static apr_hash_t *drivers = NULL;
63 static apr_uint32_t initialised = 0, in_init = 1;
64
65 static apr_status_t dbm_term(void *ptr)
66 {
67     /* set drivers to NULL so init can work again */
68     drivers = NULL;
69
70     /* Everything else we need is handled by cleanups registered
71      * when we created mutexes and loaded DSOs
72      */
73     return APR_SUCCESS;
74 }
75
76 #endif /* APU_DSO_BUILD */
77
78 static apr_status_t dbm_open_type(apr_dbm_type_t const* * vtable,
79                                   const char *type, 
80                                   apr_pool_t *pool)
81 {
82 #if !APU_DSO_BUILD
83
84     *vtable = NULL;
85     if (!strcasecmp(type, "default"))     *vtable = &DBM_VTABLE;
86 #if APU_HAVE_DB
87     else if (!strcasecmp(type, "db"))     *vtable = &apr_dbm_type_db;
88 #endif
89     else if (*type && !strcasecmp(type + 1, "dbm")) {
90 #if APU_HAVE_GDBM
91         if (*type == 'G' || *type == 'g') *vtable = &apr_dbm_type_gdbm;
92 #endif
93 #if APU_HAVE_NDBM
94         if (*type == 'N' || *type == 'n') *vtable = &apr_dbm_type_ndbm;
95 #endif
96 #if APU_HAVE_SDBM
97         if (*type == 'S' || *type == 's') *vtable = &apr_dbm_type_sdbm;
98 #endif
99         /* avoid empty block */ ;
100     }
101     if (*vtable)
102         return APR_SUCCESS;
103     return APR_ENOTIMPL;
104
105 #else /* APU_DSO_BUILD */
106
107     char modname[32];
108     char symname[34];
109     apr_dso_handle_sym_t symbol;
110     apr_status_t rv;
111     int usertype = 0;
112
113     if (!strcasecmp(type, "default"))        type = DBM_NAME;
114     else if (!strcasecmp(type, "db"))        type = "db";
115     else if (*type && !strcasecmp(type + 1, "dbm")) {
116         if      (*type == 'G' || *type == 'g') type = "gdbm"; 
117         else if (*type == 'N' || *type == 'n') type = "ndbm"; 
118         else if (*type == 'S' || *type == 's') type = "sdbm"; 
119     }
120     else usertype = 1;
121
122     if (apr_atomic_inc32(&initialised)) {
123         apr_atomic_set32(&initialised, 1); /* prevent wrap-around */
124
125         while (apr_atomic_read32(&in_init)) /* wait until we get fully inited */
126             ;
127     }
128     else {
129         apr_pool_t *parent;
130
131         /* Top level pool scope, need process-scope lifetime */
132         for (parent = apr_pool_parent_get(pool);
133              parent && parent != pool;
134              parent = apr_pool_parent_get(pool))
135             pool = parent;
136
137         /* deprecate in 2.0 - permit implicit initialization */
138         apu_dso_init(pool);
139
140         drivers = apr_hash_make(pool);
141         apr_hash_set(drivers, "sdbm", APR_HASH_KEY_STRING, &apr_dbm_type_sdbm);
142
143         apr_pool_cleanup_register(pool, NULL, dbm_term,
144                                   apr_pool_cleanup_null);
145
146         apr_atomic_dec32(&in_init);
147     }
148
149     rv = apu_dso_mutex_lock();
150     if (rv) {
151         *vtable = NULL;
152         return rv;
153     }
154
155     *vtable = apr_hash_get(drivers, type, APR_HASH_KEY_STRING);
156     if (*vtable) {
157         apu_dso_mutex_unlock();
158         return APR_SUCCESS;
159     }
160
161     /* The driver DSO must have exactly the same lifetime as the
162      * drivers hash table; ignore the passed-in pool */
163     pool = apr_hash_pool_get(drivers);
164
165 #if defined(NETWARE)
166     apr_snprintf(modname, sizeof(modname), "dbm%s.nlm", type);
167 #elif defined(WIN32) || defined (__CYGWIN__)
168     apr_snprintf(modname, sizeof(modname),
169                  "apr_dbm_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".dll", type);
170 #else
171     apr_snprintf(modname, sizeof(modname),
172                  "apr_dbm_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".so", type);
173 #endif
174     apr_snprintf(symname, sizeof(symname), "apr_dbm_type_%s", type);
175
176     rv = apu_dso_load(NULL, &symbol, modname, symname, pool);
177     if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */
178         *vtable = symbol;
179         if (usertype)
180             type = apr_pstrdup(pool, type);
181         apr_hash_set(drivers, type, APR_HASH_KEY_STRING, *vtable);
182         rv = APR_SUCCESS;
183     }
184     else
185         *vtable = NULL;
186
187     apu_dso_mutex_unlock();
188     return rv;
189
190 #endif /* APU_DSO_BUILD */
191 }
192
193 APU_DECLARE(apr_status_t) apr_dbm_open_ex(apr_dbm_t **pdb, const char *type, 
194                                           const char *pathname, 
195                                           apr_int32_t mode,
196                                           apr_fileperms_t perm,
197                                           apr_pool_t *pool)
198 {
199     apr_dbm_type_t const* vtable = NULL;
200     apr_status_t rv = dbm_open_type(&vtable, type, pool);
201
202     if (rv == APR_SUCCESS) {
203         rv = (vtable->open)(pdb, pathname, mode, perm, pool);
204     }
205     return rv;
206
207
208 APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **pdb, const char *pathname, 
209                                        apr_int32_t mode, apr_fileperms_t perm,
210                                        apr_pool_t *pool)
211 {
212     return apr_dbm_open_ex(pdb, DBM_NAME, pathname, mode, perm, pool);
213 }
214
215 APU_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm)
216 {
217     (*dbm->type->close)(dbm);
218 }
219
220 APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key,
221                                         apr_datum_t *pvalue)
222 {
223     return (*dbm->type->fetch)(dbm, key, pvalue);
224 }
225
226 APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key,
227                                         apr_datum_t value)
228 {
229     return (*dbm->type->store)(dbm, key, value);
230 }
231
232 APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key)
233 {
234     return (*dbm->type->del)(dbm, key);
235 }
236
237 APU_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key)
238 {
239     return (*dbm->type->exists)(dbm, key);
240 }
241
242 APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey)
243 {
244     return (*dbm->type->firstkey)(dbm, pkey);
245 }
246
247 APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey)
248 {
249     return (*dbm->type->nextkey)(dbm, pkey);
250 }
251
252 APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data)
253 {
254     (*dbm->type->freedatum)(dbm, data);
255 }
256
257 APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode,
258                                      char *errbuf, apr_size_t errbufsize)
259 {
260     if (errcode != NULL)
261         *errcode = dbm->errcode;
262
263     /* assert: errbufsize > 0 */
264
265     if (dbm->errmsg == NULL)
266         *errbuf = '\0';
267     else
268         (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize);
269     return errbuf;
270 }
271
272 APU_DECLARE(apr_status_t) apr_dbm_get_usednames_ex(apr_pool_t *p, 
273                                                    const char *type, 
274                                                    const char *pathname,
275                                                    const char **used1,
276                                                    const char **used2)
277 {
278     apr_dbm_type_t const* vtable;
279     apr_status_t rv = dbm_open_type(&vtable, type, p);
280
281     if (rv == APR_SUCCESS) {
282         (vtable->getusednames)(p, pathname, used1, used2);
283         return APR_SUCCESS;
284     }
285     return rv;
286
287
288 APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *p,
289                                         const char *pathname,
290                                         const char **used1,
291                                         const char **used2)
292 {
293     apr_dbm_get_usednames_ex(p, DBM_NAME, pathname, used1, used2); 
294 }
295
296 /* Most DBM libraries take a POSIX mode for creating files.  Don't trust
297  * the mode_t type, some platforms may not support it, int is safe.
298  */
299 APU_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm)
300 {
301     int mode = 0;
302
303     mode |= 0700 & (perm >> 2); /* User  is off-by-2 bits */
304     mode |= 0070 & (perm >> 1); /* Group is off-by-1 bit */
305     mode |= 0007 & (perm);      /* World maps 1 for 1 */
306     return mode;
307 }