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