1 /* $OpenBSD: ndbm.c,v 1.21 2005/08/08 08:05:33 espie Exp $ */
2
3 /*-
4 * Copyright © 2013
5 * Thorsten “mirabilos” Glaser <tg@mirbsd.org>
6 * Copyright (c) 1990, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Margo Seltzer.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/param.h>
38
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <string.h>
43
44 #include <ndbm.h>
45 #include <dbm.h>
46 #include "hash.h"
47
48 __RCSID("$MirOS: src/lib/libc/db/hash/ndbm.c,v 1.3 2013/10/31 20:06:16 tg Exp $");
49
50 /*
51 *
52 * This package provides dbm and ndbm compatible interfaces to DB.
53 * First are the DBM routines, which call the NDBM routines, and
54 * the NDBM routines, which call the DB routines.
55 */
56 static DBM *__cur_db;
57
58 static DBM *_dbm_open(const char *, const char *, int, mode_t);
59
60 /*
61 * Returns:
62 * 0 on success
63 * <0 on failure
64 */
65 int
dbminit(const char * file)66 dbminit(const char *file)
67 {
68
69 if (__cur_db != NULL)
70 (void)dbm_close(__cur_db);
71 if ((__cur_db = _dbm_open(file, ".pag", O_RDWR, 0)) != NULL)
72 return (0);
73 if ((__cur_db = _dbm_open(file, ".pag", O_RDONLY, 0)) != NULL)
74 return (0);
75 return (-1);
76 }
77
78 /*
79 * Returns:
80 * 0 on success
81 * <0 on failure
82 */
83 int
dbmclose(void)84 dbmclose(void)
85 {
86 int rval;
87
88 if (__cur_db == NULL)
89 return (-1);
90 rval = (__cur_db->close)(__cur_db);
91 __cur_db = NULL;
92 return (rval);
93 }
94
95 /*
96 * Returns:
97 * DATUM on success
98 * NULL on failure
99 */
100 datum
fetch(datum key)101 fetch(datum key)
102 {
103 datum item;
104
105 if (__cur_db == NULL) {
106 item.dptr = NULL;
107 item.dsize = 0;
108 return (item);
109 }
110 return (dbm_fetch(__cur_db, key));
111 }
112
113 /*
114 * Returns:
115 * DATUM on success
116 * NULL on failure
117 */
118 datum
firstkey(void)119 firstkey(void)
120 {
121 datum item;
122
123 if (__cur_db == NULL) {
124 item.dptr = NULL;
125 item.dsize = 0;
126 return (item);
127 }
128 return (dbm_firstkey(__cur_db));
129 }
130
131 /*
132 * Returns:
133 * DATUM on success
134 * NULL on failure
135 */
136 /* ARGSUSED */
137 datum
nextkey(datum key)138 nextkey(datum key __attribute__((__unused__)))
139 {
140 datum item;
141
142 if (__cur_db == NULL) {
143 item.dptr = NULL;
144 item.dsize = 0;
145 return (item);
146 }
147 return (dbm_nextkey(__cur_db));
148 }
149
150 /*
151 * Returns:
152 * 0 on success
153 * <0 on failure
154 */
155 int
delete(datum key)156 delete(datum key)
157 {
158
159 if (__cur_db == NULL || dbm_rdonly(__cur_db))
160 return (-1);
161 return (dbm_delete(__cur_db, key));
162 }
163
164 /*
165 * Returns:
166 * 0 on success
167 * <0 on failure
168 */
169 int
store(datum key,datum dat)170 store(datum key, datum dat)
171 {
172
173 if (__cur_db == NULL || dbm_rdonly(__cur_db))
174 return (-1);
175 return (dbm_store(__cur_db, key, dat, DBM_REPLACE));
176 }
177
178 /*
179 * Returns:
180 * *DBM on success
181 * NULL on failure
182 */
183 static DBM *
_dbm_open(const char * file,const char * suff,int flags,mode_t mode)184 _dbm_open(const char *file, const char *suff, int flags, mode_t mode)
185 {
186 HASHINFO info;
187 char path[MAXPATHLEN];
188
189 if (strlen(file) + strlen(suff) > sizeof(path) - 1) {
190 errno = ENAMETOOLONG;
191 return (NULL);
192 }
193 /* O_WRONLY not supported by db(3) but traditional ndbm allowed it. */
194 if ((flags & O_ACCMODE) == O_WRONLY) {
195 flags &= ~O_WRONLY;
196 flags |= O_RDWR;
197 }
198 info.bsize = 4096;
199 info.ffactor = 40;
200 info.nelem = 1;
201 info.cachesize = 0;
202 info.hash = NULL;
203 info.lorder = 0;
204 snprintf(path, sizeof path, "%s%s", file, suff);
205 return ((DBM *)__hash_open(path, flags, mode, &info, 0));
206 }
207
208 /*
209 * Returns:
210 * *DBM on success
211 * NULL on failure
212 */
213 DBM *
dbm_open(const char * file,int flags,mode_t mode)214 dbm_open(const char *file, int flags, mode_t mode)
215 {
216
217 return(_dbm_open(file, DBM_SUFFIX, flags, mode));
218 }
219
220 /*
221 * Returns:
222 * Nothing.
223 */
224 void
dbm_close(DBM * db)225 dbm_close(DBM *db)
226 {
227 (void)(db->close)(db);
228 }
229
230 /*
231 * Returns:
232 * DATUM on success
233 * NULL on failure
234 */
235 datum
dbm_fetch(DBM * db,datum key)236 dbm_fetch(DBM *db, datum key)
237 {
238 datum retdata;
239 int status;
240 DBT dbtkey, dbtretdata;
241
242 dbtkey.data = key.dptr;
243 dbtkey.size = key.dsize;
244 status = (db->get)(db, &dbtkey, &dbtretdata, 0);
245 if (status) {
246 dbtretdata.data = NULL;
247 dbtretdata.size = 0;
248 }
249 retdata.dptr = dbtretdata.data;
250 retdata.dsize = dbtretdata.size;
251 return (retdata);
252 }
253
254 /*
255 * Returns:
256 * DATUM on success
257 * NULL on failure
258 */
259 datum
dbm_firstkey(DBM * db)260 dbm_firstkey(DBM *db)
261 {
262 int status;
263 datum retkey;
264 DBT dbtretkey, dbtretdata;
265
266 status = (db->seq)(db, &dbtretkey, &dbtretdata, R_FIRST);
267 if (status)
268 dbtretkey.data = NULL;
269 retkey.dptr = dbtretkey.data;
270 retkey.dsize = dbtretkey.size;
271 return (retkey);
272 }
273
274 /*
275 * Returns:
276 * DATUM on success
277 * NULL on failure
278 */
279 datum
dbm_nextkey(DBM * db)280 dbm_nextkey(DBM *db)
281 {
282 int status;
283 datum retkey;
284 DBT dbtretkey, dbtretdata;
285
286 status = (db->seq)(db, &dbtretkey, &dbtretdata, R_NEXT);
287 if (status)
288 dbtretkey.data = NULL;
289 retkey.dptr = dbtretkey.data;
290 retkey.dsize = dbtretkey.size;
291 return (retkey);
292 }
293
294 /*
295 * Returns:
296 * 0 on success
297 * <0 on failure
298 */
299 int
dbm_delete(DBM * db,datum key)300 dbm_delete(DBM *db, datum key)
301 {
302 int status;
303 DBT dbtkey;
304
305 dbtkey.data = key.dptr;
306 dbtkey.size = key.dsize;
307 status = (db->del)(db, &dbtkey, 0);
308 if (status)
309 return (-1);
310 else
311 return (0);
312 }
313
314 /*
315 * Returns:
316 * 0 on success
317 * <0 on failure
318 * 1 if DBM_INSERT and entry exists
319 */
320 int
dbm_store(DBM * db,datum key,datum data,int flags)321 dbm_store(DBM *db, datum key, datum data, int flags)
322 {
323 DBT dbtkey, dbtdata;
324
325 dbtkey.data = key.dptr;
326 dbtkey.size = key.dsize;
327 dbtdata.data = data.dptr;
328 dbtdata.size = data.dsize;
329 return ((db->put)(db, &dbtkey, &dbtdata,
330 (flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
331 }
332
333 int
dbm_error(DBM * db)334 dbm_error(DBM *db)
335 {
336 HTAB *hp;
337
338 hp = (HTAB *)db->internal;
339 return (hp->err);
340 }
341
342 int
dbm_clearerr(DBM * db)343 dbm_clearerr(DBM *db)
344 {
345 HTAB *hp;
346
347 hp = (HTAB *)db->internal;
348 hp->err = 0;
349 return (0);
350 }
351
352 int
dbm_dirfno(DBM * db)353 dbm_dirfno(DBM *db)
354 {
355 return(((HTAB *)db->internal)->fp);
356 }
357
358 int
dbm_rdonly(DBM * dbp)359 dbm_rdonly(DBM *dbp)
360 {
361 HTAB *hashp = (HTAB *)dbp->internal;
362
363 /* Could use DBM_RDONLY instead if we wanted... */
364 return ((hashp->flags & O_ACCMODE) == O_RDONLY);
365 }
366