add packaging
[platform/upstream/db4.git] / dbm / dbm.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5  */
6 /*
7  * Copyright (c) 1990, 1993
8  *      Margo Seltzer.  All rights reserved.
9  */
10 /*
11  * Copyright (c) 1990, 1993
12  *      The Regents of the University of California.  All rights reserved.
13  *
14  * This code is derived from software contributed to Berkeley by
15  * Margo Seltzer.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  * $Id$
42  */
43
44 #define DB_DBM_HSEARCH  1
45 #include "db_config.h"
46
47 #include "db_int.h"
48
49 /*
50  *
51  * This package provides dbm and ndbm compatible interfaces to DB.
52  *
53  * EXTERN: #if DB_DBM_HSEARCH != 0
54  *
55  * EXTERN: int   __db_ndbm_clearerr __P((DBM *));
56  * EXTERN: void  __db_ndbm_close __P((DBM *));
57  * EXTERN: int   __db_ndbm_delete __P((DBM *, datum));
58  * EXTERN: int   __db_ndbm_dirfno __P((DBM *));
59  * EXTERN: int   __db_ndbm_error __P((DBM *));
60  * EXTERN: datum __db_ndbm_fetch __P((DBM *, datum));
61  * EXTERN: datum __db_ndbm_firstkey __P((DBM *));
62  * EXTERN: datum __db_ndbm_nextkey __P((DBM *));
63  * EXTERN: DBM  *__db_ndbm_open __P((const char *, int, int));
64  * EXTERN: int   __db_ndbm_pagfno __P((DBM *));
65  * EXTERN: int   __db_ndbm_rdonly __P((DBM *));
66  * EXTERN: int   __db_ndbm_store __P((DBM *, datum, datum, int));
67  *
68  * EXTERN: int   __db_dbm_close __P((void));
69  * EXTERN: int   __db_dbm_delete __P((datum));
70  * EXTERN: datum __db_dbm_fetch __P((datum));
71  * EXTERN: datum __db_dbm_firstkey __P((void));
72  * EXTERN: int   __db_dbm_init __P((char *));
73  * EXTERN: datum __db_dbm_nextkey __P((datum));
74  * EXTERN: int   __db_dbm_store __P((datum, datum));
75  *
76  * EXTERN: #endif
77  */
78
79 /*
80  * The DBM routines, which call the NDBM routines.
81  */
82 static DBM *__cur_db;
83
84 static void __db_no_open __P((void));
85
86 int
87 __db_dbm_init(file)
88         char *file;
89 {
90         if (__cur_db != NULL)
91                 dbm_close(__cur_db);
92         if ((__cur_db = dbm_open(file, O_CREAT | O_RDWR, DB_MODE_600)) != NULL)
93                 return (0);
94         if ((__cur_db = dbm_open(file, O_RDONLY, 0)) != NULL)
95                 return (0);
96         return (-1);
97 }
98
99 int
100 __db_dbm_close()
101 {
102         if (__cur_db != NULL) {
103                 dbm_close(__cur_db);
104                 __cur_db = NULL;
105         }
106         return (0);
107 }
108
109 datum
110 __db_dbm_fetch(key)
111         datum key;
112 {
113         datum item;
114
115         if (__cur_db == NULL) {
116                 __db_no_open();
117                 item.dptr = NULL;
118                 item.dsize = 0;
119                 return (item);
120         }
121         return (dbm_fetch(__cur_db, key));
122 }
123
124 datum
125 __db_dbm_firstkey()
126 {
127         datum item;
128
129         if (__cur_db == NULL) {
130                 __db_no_open();
131                 item.dptr = NULL;
132                 item.dsize = 0;
133                 return (item);
134         }
135         return (dbm_firstkey(__cur_db));
136 }
137
138 datum
139 __db_dbm_nextkey(key)
140         datum key;
141 {
142         datum item;
143
144         COMPQUIET(key.dsize, 0);
145
146         if (__cur_db == NULL) {
147                 __db_no_open();
148                 item.dptr = NULL;
149                 item.dsize = 0;
150                 return (item);
151         }
152         return (dbm_nextkey(__cur_db));
153 }
154
155 int
156 __db_dbm_delete(key)
157         datum key;
158 {
159         if (__cur_db == NULL) {
160                 __db_no_open();
161                 return (-1);
162         }
163         return (dbm_delete(__cur_db, key));
164 }
165
166 int
167 __db_dbm_store(key, dat)
168         datum key, dat;
169 {
170         if (__cur_db == NULL) {
171                 __db_no_open();
172                 return (-1);
173         }
174         return (dbm_store(__cur_db, key, dat, DBM_REPLACE));
175 }
176
177 static void
178 __db_no_open()
179 {
180         (void)fprintf(stderr, "dbm: no open database.\n");
181 }
182
183 /*
184  * This package provides dbm and ndbm compatible interfaces to DB.
185  *
186  * The NDBM routines, which call the DB routines.
187  */
188 /*
189  * Returns:
190  *      *DBM on success
191  *       NULL on failure
192  */
193 DBM *
194 __db_ndbm_open(file, oflags, mode)
195         const char *file;
196         int oflags, mode;
197 {
198         DB *dbp;
199         DBC *dbc;
200         int ret;
201         char path[DB_MAXPATHLEN];
202
203         /*
204          * !!!
205          * Don't use sprintf(3)/snprintf(3) -- the former is dangerous, and
206          * the latter isn't standard, and we're manipulating strings handed
207          * us by the application.
208          */
209         if (strlen(file) + strlen(DBM_SUFFIX) + 1 > sizeof(path)) {
210                 __os_set_errno(ENAMETOOLONG);
211                 return (NULL);
212         }
213         (void)strcpy(path, file);
214         (void)strcat(path, DBM_SUFFIX);
215         if ((ret = db_create(&dbp, NULL, 0)) != 0) {
216                 __os_set_errno(ret);
217                 return (NULL);
218         }
219
220         /*
221          * !!!
222          * The historic ndbm library corrected for opening O_WRONLY.
223          */
224         if (oflags & O_WRONLY) {
225                 oflags &= ~O_WRONLY;
226                 oflags |= O_RDWR;
227         }
228
229         if ((ret = dbp->set_pagesize(dbp, 4096)) != 0 ||
230             (ret = dbp->set_h_ffactor(dbp, 40)) != 0 ||
231             (ret = dbp->set_h_nelem(dbp, 1)) != 0 ||
232             (ret = dbp->open(dbp, NULL,
233             path, NULL, DB_HASH, __db_openflags(oflags), mode)) != 0) {
234                 __os_set_errno(ret);
235                 return (NULL);
236         }
237
238         if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) {
239                 (void)dbp->close(dbp, 0);
240                 __os_set_errno(ret);
241                 return (NULL);
242         }
243
244         return ((DBM *)dbc);
245 }
246
247 /*
248  * Returns:
249  *      Nothing.
250  */
251 void
252 __db_ndbm_close(dbm)
253         DBM *dbm;
254 {
255         DBC *dbc;
256
257         dbc = (DBC *)dbm;
258
259         (void)dbc->dbp->close(dbc->dbp, 0);
260 }
261
262 /*
263  * Returns:
264  *      DATUM on success
265  *      NULL on failure
266  */
267 datum
268 __db_ndbm_fetch(dbm, key)
269         DBM *dbm;
270         datum key;
271 {
272         DBC *dbc;
273         DBT _key, _data;
274         datum data;
275         int ret;
276
277         dbc = (DBC *)dbm;
278
279         DB_INIT_DBT(_key, key.dptr, key.dsize);
280         memset(&_data, 0, sizeof(DBT));
281
282         /*
283          * Note that we can't simply use the dbc we have to do a get/SET,
284          * because that cursor is the one used for sequential iteration and
285          * it has to remain stable in the face of intervening gets and puts.
286          */
287         if ((ret = dbc->dbp->get(dbc->dbp, NULL, &_key, &_data, 0)) == 0) {
288                 data.dptr = _data.data;
289                 data.dsize = (int)_data.size;
290         } else {
291                 data.dptr = NULL;
292                 data.dsize = 0;
293                 if (ret == DB_NOTFOUND)
294                         __os_set_errno(ENOENT);
295                 else {
296                         __os_set_errno(ret);
297                         F_SET(dbc->dbp, DB_AM_DBM_ERROR);
298                 }
299         }
300         return (data);
301 }
302
303 /*
304  * Returns:
305  *      DATUM on success
306  *      NULL on failure
307  */
308 datum
309 __db_ndbm_firstkey(dbm)
310         DBM *dbm;
311 {
312         DBC *dbc;
313         DBT _key, _data;
314         datum key;
315         int ret;
316
317         dbc = (DBC *)dbm;
318
319         memset(&_key, 0, sizeof(DBT));
320         memset(&_data, 0, sizeof(DBT));
321
322         if ((ret = dbc->get(dbc, &_key, &_data, DB_FIRST)) == 0) {
323                 key.dptr = _key.data;
324                 key.dsize = (int)_key.size;
325         } else {
326                 key.dptr = NULL;
327                 key.dsize = 0;
328                 if (ret == DB_NOTFOUND)
329                         __os_set_errno(ENOENT);
330                 else {
331                         __os_set_errno(ret);
332                         F_SET(dbc->dbp, DB_AM_DBM_ERROR);
333                 }
334         }
335         return (key);
336 }
337
338 /*
339  * Returns:
340  *      DATUM on success
341  *      NULL on failure
342  */
343 datum
344 __db_ndbm_nextkey(dbm)
345         DBM *dbm;
346 {
347         DBC *dbc;
348         DBT _key, _data;
349         datum key;
350         int ret;
351
352         dbc = (DBC *)dbm;
353
354         memset(&_key, 0, sizeof(DBT));
355         memset(&_data, 0, sizeof(DBT));
356
357         if ((ret = dbc->get(dbc, &_key, &_data, DB_NEXT)) == 0) {
358                 key.dptr = _key.data;
359                 key.dsize = (int)_key.size;
360         } else {
361                 key.dptr = NULL;
362                 key.dsize = 0;
363                 if (ret == DB_NOTFOUND)
364                         __os_set_errno(ENOENT);
365                 else {
366                         __os_set_errno(ret);
367                         F_SET(dbc->dbp, DB_AM_DBM_ERROR);
368                 }
369         }
370         return (key);
371 }
372
373 /*
374  * Returns:
375  *       0 on success
376  *      <0 failure
377  */
378 int
379 __db_ndbm_delete(dbm, key)
380         DBM *dbm;
381         datum key;
382 {
383         DBC *dbc;
384         DBT _key;
385         int ret;
386
387         dbc = (DBC *)dbm;
388
389         DB_INIT_DBT(_key, key.dptr, key.dsize);
390
391         if ((ret = dbc->dbp->del(dbc->dbp, NULL, &_key, 0)) == 0)
392                 return (0);
393
394         if (ret == DB_NOTFOUND)
395                 __os_set_errno(ENOENT);
396         else {
397                 __os_set_errno(ret);
398                 F_SET(dbc->dbp, DB_AM_DBM_ERROR);
399         }
400         return (-1);
401 }
402
403 /*
404  * Returns:
405  *       0 on success
406  *      <0 failure
407  *       1 if DBM_INSERT and entry exists
408  */
409 int
410 __db_ndbm_store(dbm, key, data, flags)
411         DBM *dbm;
412         datum key, data;
413         int flags;
414 {
415         DBC *dbc;
416         DBT _key, _data;
417         int ret;
418
419         dbc = (DBC *)dbm;
420
421         DB_INIT_DBT(_key, key.dptr, key.dsize);
422         DB_INIT_DBT(_data, data.dptr, data.dsize);
423
424         if ((ret = dbc->dbp->put(dbc->dbp, NULL,
425             &_key, &_data, flags == DBM_INSERT ? DB_NOOVERWRITE : 0)) == 0)
426                 return (0);
427
428         if (ret == DB_KEYEXIST)
429                 return (1);
430
431         __os_set_errno(ret);
432         F_SET(dbc->dbp, DB_AM_DBM_ERROR);
433         return (-1);
434 }
435
436 int
437 __db_ndbm_error(dbm)
438         DBM *dbm;
439 {
440         DBC *dbc;
441
442         dbc = (DBC *)dbm;
443
444         return (F_ISSET(dbc->dbp, DB_AM_DBM_ERROR));
445 }
446
447 int
448 __db_ndbm_clearerr(dbm)
449         DBM *dbm;
450 {
451         DBC *dbc;
452
453         dbc = (DBC *)dbm;
454
455         F_CLR(dbc->dbp, DB_AM_DBM_ERROR);
456         return (0);
457 }
458
459 /*
460  * Returns:
461  *      1 if read-only
462  *      0 if not read-only
463  */
464 int
465 __db_ndbm_rdonly(dbm)
466         DBM *dbm;
467 {
468         DBC *dbc;
469
470         dbc = (DBC *)dbm;
471
472         return (F_ISSET(dbc->dbp, DB_AM_RDONLY) ? 1 : 0);
473 }
474
475 /*
476  * XXX
477  * We only have a single file descriptor that we can return, not two.  Return
478  * the same one for both files.  Hopefully, the user is using it for locking
479  * and picked one to use at random.
480  */
481 int
482 __db_ndbm_dirfno(dbm)
483         DBM *dbm;
484 {
485         return (dbm_pagfno(dbm));
486 }
487
488 int
489 __db_ndbm_pagfno(dbm)
490         DBM *dbm;
491 {
492         DBC *dbc;
493         int fd;
494
495         dbc = (DBC *)dbm;
496
497         (void)dbc->dbp->fd(dbc->dbp, &fd);
498         return (fd);
499 }