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