1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 2013 Oracle and/or its affiliates. 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 #include "db_config.h"
45
46 #include "db_int.h"
47
48 /*
49 *
50 * This package provides dbm and ndbm compatible interfaces to DB.
51 *
52 * EXTERN: #if DB_DBM_HSEARCH != 0
53 * EXTERN: int __db_ndbm_clearerr __P((DBM *));
54 * EXTERN: void __db_ndbm_close __P((DBM *));
55 * EXTERN: int __db_ndbm_delete __P((DBM *, datum));
56 * EXTERN: int __db_ndbm_dirfno __P((DBM *));
57 * EXTERN: int __db_ndbm_error __P((DBM *));
58 * EXTERN: datum __db_ndbm_fetch __P((DBM *, datum));
59 * EXTERN: datum __db_ndbm_firstkey __P((DBM *));
60 * EXTERN: datum __db_ndbm_nextkey __P((DBM *));
61 * EXTERN: DBM *__db_ndbm_open __P((const char *, int, int));
62 * EXTERN: int __db_ndbm_pagfno __P((DBM *));
63 * EXTERN: int __db_ndbm_rdonly __P((DBM *));
64 * EXTERN: int __db_ndbm_store __P((DBM *, datum, datum, int));
65 *
66 * EXTERN: int __db_dbm_close __P((void));
67 * EXTERN: int __db_dbm_delete __P((datum));
68 * EXTERN: datum __db_dbm_fetch __P((datum));
69 * EXTERN: datum __db_dbm_firstkey __P((void));
70 * EXTERN: int __db_dbm_init __P((char *));
71 * EXTERN: datum __db_dbm_nextkey __P((datum));
72 * EXTERN: int __db_dbm_store __P((datum, datum));
73 * EXTERN: #endif
74 */
75
76 /*
77 * The DBM routines, which call the NDBM routines.
78 */
79 static DBM *__cur_db;
80
81 static void __db_no_open __P((void));
82
83 int
__db_dbm_init(file)84 __db_dbm_init(file)
85 char *file;
86 {
87 if (__cur_db != NULL)
88 dbm_close(__cur_db);
89 if ((__cur_db = dbm_open(file, O_CREAT | O_RDWR, DB_MODE_600)) != NULL)
90 return (0);
91 if ((__cur_db = dbm_open(file, O_RDONLY, 0)) != NULL)
92 return (0);
93 return (-1);
94 }
95
96 int
__db_dbm_close()97 __db_dbm_close()
98 {
99 if (__cur_db != NULL) {
100 dbm_close(__cur_db);
101 __cur_db = NULL;
102 }
103 return (0);
104 }
105
106 datum
__db_dbm_fetch(key)107 __db_dbm_fetch(key)
108 datum key;
109 {
110 datum item;
111
112 if (__cur_db == NULL) {
113 __db_no_open();
114 item.dptr = NULL;
115 item.dsize = 0;
116 return (item);
117 }
118 return (dbm_fetch(__cur_db, key));
119 }
120
121 datum
__db_dbm_firstkey()122 __db_dbm_firstkey()
123 {
124 datum item;
125
126 if (__cur_db == NULL) {
127 __db_no_open();
128 item.dptr = NULL;
129 item.dsize = 0;
130 return (item);
131 }
132 return (dbm_firstkey(__cur_db));
133 }
134
135 datum
__db_dbm_nextkey(key)136 __db_dbm_nextkey(key)
137 datum key;
138 {
139 datum item;
140
141 COMPQUIET(key.dsize, 0);
142
143 if (__cur_db == NULL) {
144 __db_no_open();
145 item.dptr = NULL;
146 item.dsize = 0;
147 return (item);
148 }
149 return (dbm_nextkey(__cur_db));
150 }
151
152 int
__db_dbm_delete(key)153 __db_dbm_delete(key)
154 datum key;
155 {
156 if (__cur_db == NULL) {
157 __db_no_open();
158 return (-1);
159 }
160 return (dbm_delete(__cur_db, key));
161 }
162
163 int
__db_dbm_store(key,dat)164 __db_dbm_store(key, dat)
165 datum key, dat;
166 {
167 if (__cur_db == NULL) {
168 __db_no_open();
169 return (-1);
170 }
171 return (dbm_store(__cur_db, key, dat, DBM_REPLACE));
172 }
173
174 static void
__db_no_open()175 __db_no_open()
176 {
177 (void)fprintf(stderr, DB_STR_A("5126",
178 "dbm: no open database.\n", "\n"));
179 }
180
181 /*
182 * This package provides dbm and ndbm compatible interfaces to DB.
183 *
184 * The NDBM routines, which call the DB routines.
185 */
186 /*
187 * Returns:
188 * *DBM on success
189 * NULL on failure
190 */
191 DBM *
__db_ndbm_open(file,oflags,mode)192 __db_ndbm_open(file, oflags, mode)
193 const char *file;
194 int oflags, mode;
195 {
196 DB *dbp;
197 DBC *dbc;
198 int ret;
199 char path[DB_MAXPATHLEN];
200
201 /*
202 * !!!
203 * Don't use sprintf(3)/snprintf(3) -- the former is dangerous, and
204 * the latter isn't standard, and we're manipulating strings handed
205 * us by the application.
206 */
207 if (strlen(file) + strlen(DBM_SUFFIX) + 1 > sizeof(path)) {
208 __os_set_errno(ENAMETOOLONG);
209 return (NULL);
210 }
211 (void)strcpy(path, file);
212 (void)strcat(path, DBM_SUFFIX);
213 if ((ret = db_create(&dbp, NULL, 0)) != 0) {
214 __os_set_errno(ret);
215 return (NULL);
216 }
217
218 /*
219 * !!!
220 * The historic ndbm library corrected for opening O_WRONLY.
221 */
222 if (oflags & O_WRONLY) {
223 oflags &= ~O_WRONLY;
224 oflags |= O_RDWR;
225 }
226
227 if ((ret = dbp->set_pagesize(dbp, 4096)) != 0 ||
228 (ret = dbp->set_h_ffactor(dbp, 40)) != 0 ||
229 (ret = dbp->set_h_nelem(dbp, 1)) != 0 ||
230 (ret = dbp->open(dbp, NULL,
231 path, NULL, DB_HASH, __db_openflags(oflags), mode)) != 0) {
232 __os_set_errno(ret);
233 return (NULL);
234 }
235
236 if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) {
237 (void)dbp->close(dbp, 0);
238 __os_set_errno(ret);
239 return (NULL);
240 }
241
242 return ((DBM *)dbc);
243 }
244
245 /*
246 * Returns:
247 * Nothing.
248 */
249 void
__db_ndbm_close(dbm)250 __db_ndbm_close(dbm)
251 DBM *dbm;
252 {
253 DBC *dbc;
254
255 dbc = (DBC *)dbm;
256
257 (void)dbc->dbp->close(dbc->dbp, 0);
258 }
259
260 /*
261 * Returns:
262 * DATUM on success
263 * NULL on failure
264 */
265 datum
__db_ndbm_fetch(dbm,key)266 __db_ndbm_fetch(dbm, key)
267 DBM *dbm;
268 datum key;
269 {
270 DBC *dbc;
271 DBT _key, _data;
272 datum data;
273 int ret;
274
275 dbc = (DBC *)dbm;
276
277 DB_INIT_DBT(_key, key.dptr, key.dsize);
278 memset(&_data, 0, sizeof(DBT));
279
280 /*
281 * Note that we can't simply use the dbc we have to do a get/SET,
282 * because that cursor is the one used for sequential iteration and
283 * it has to remain stable in the face of intervening gets and puts.
284 */
285 if ((ret = dbc->dbp->get(dbc->dbp, NULL, &_key, &_data, 0)) == 0) {
286 data.dptr = _data.data;
287 data.dsize = (int)_data.size;
288 } else {
289 data.dptr = NULL;
290 data.dsize = 0;
291 if (ret == DB_NOTFOUND)
292 __os_set_errno(ENOENT);
293 else {
294 __os_set_errno(ret);
295 F_SET(dbc->dbp, DB_AM_DBM_ERROR);
296 }
297 }
298 return (data);
299 }
300
301 /*
302 * Returns:
303 * DATUM on success
304 * NULL on failure
305 */
306 datum
__db_ndbm_firstkey(dbm)307 __db_ndbm_firstkey(dbm)
308 DBM *dbm;
309 {
310 DBC *dbc;
311 DBT _key, _data;
312 datum key;
313 int ret;
314
315 dbc = (DBC *)dbm;
316
317 memset(&_key, 0, sizeof(DBT));
318 memset(&_data, 0, sizeof(DBT));
319
320 if ((ret = dbc->get(dbc, &_key, &_data, DB_FIRST)) == 0) {
321 key.dptr = _key.data;
322 key.dsize = (int)_key.size;
323 } else {
324 key.dptr = NULL;
325 key.dsize = 0;
326 if (ret == DB_NOTFOUND)
327 __os_set_errno(ENOENT);
328 else {
329 __os_set_errno(ret);
330 F_SET(dbc->dbp, DB_AM_DBM_ERROR);
331 }
332 }
333 return (key);
334 }
335
336 /*
337 * Returns:
338 * DATUM on success
339 * NULL on failure
340 */
341 datum
__db_ndbm_nextkey(dbm)342 __db_ndbm_nextkey(dbm)
343 DBM *dbm;
344 {
345 DBC *dbc;
346 DBT _key, _data;
347 datum key;
348 int ret;
349
350 dbc = (DBC *)dbm;
351
352 memset(&_key, 0, sizeof(DBT));
353 memset(&_data, 0, sizeof(DBT));
354
355 if ((ret = dbc->get(dbc, &_key, &_data, DB_NEXT)) == 0) {
356 key.dptr = _key.data;
357 key.dsize = (int)_key.size;
358 } else {
359 key.dptr = NULL;
360 key.dsize = 0;
361 if (ret == DB_NOTFOUND)
362 __os_set_errno(ENOENT);
363 else {
364 __os_set_errno(ret);
365 F_SET(dbc->dbp, DB_AM_DBM_ERROR);
366 }
367 }
368 return (key);
369 }
370
371 /*
372 * Returns:
373 * 0 on success
374 * <0 failure
375 */
376 int
__db_ndbm_delete(dbm,key)377 __db_ndbm_delete(dbm, key)
378 DBM *dbm;
379 datum key;
380 {
381 DBC *dbc;
382 DBT _key;
383 int ret;
384
385 dbc = (DBC *)dbm;
386
387 DB_INIT_DBT(_key, key.dptr, key.dsize);
388
389 if ((ret = dbc->dbp->del(dbc->dbp, NULL, &_key, 0)) == 0)
390 return (0);
391
392 if (ret == DB_NOTFOUND)
393 __os_set_errno(ENOENT);
394 else {
395 __os_set_errno(ret);
396 F_SET(dbc->dbp, DB_AM_DBM_ERROR);
397 }
398 return (-1);
399 }
400
401 /*
402 * Returns:
403 * 0 on success
404 * <0 failure
405 * 1 if DBM_INSERT and entry exists
406 */
407 int
__db_ndbm_store(dbm,key,data,flags)408 __db_ndbm_store(dbm, key, data, flags)
409 DBM *dbm;
410 datum key, data;
411 int flags;
412 {
413 DBC *dbc;
414 DBT _key, _data;
415 int ret;
416
417 dbc = (DBC *)dbm;
418
419 DB_INIT_DBT(_key, key.dptr, key.dsize);
420 DB_INIT_DBT(_data, data.dptr, data.dsize);
421
422 if ((ret = dbc->dbp->put(dbc->dbp, NULL,
423 &_key, &_data, flags == DBM_INSERT ? DB_NOOVERWRITE : 0)) == 0)
424 return (0);
425
426 if (ret == DB_KEYEXIST)
427 return (1);
428
429 __os_set_errno(ret);
430 F_SET(dbc->dbp, DB_AM_DBM_ERROR);
431 return (-1);
432 }
433
434 int
__db_ndbm_error(dbm)435 __db_ndbm_error(dbm)
436 DBM *dbm;
437 {
438 DBC *dbc;
439
440 dbc = (DBC *)dbm;
441
442 return (F_ISSET(dbc->dbp, DB_AM_DBM_ERROR));
443 }
444
445 int
__db_ndbm_clearerr(dbm)446 __db_ndbm_clearerr(dbm)
447 DBM *dbm;
448 {
449 DBC *dbc;
450
451 dbc = (DBC *)dbm;
452
453 F_CLR(dbc->dbp, DB_AM_DBM_ERROR);
454 return (0);
455 }
456
457 /*
458 * Returns:
459 * 1 if read-only
460 * 0 if not read-only
461 */
462 int
__db_ndbm_rdonly(dbm)463 __db_ndbm_rdonly(dbm)
464 DBM *dbm;
465 {
466 DBC *dbc;
467
468 dbc = (DBC *)dbm;
469
470 return (F_ISSET(dbc->dbp, DB_AM_RDONLY) ? 1 : 0);
471 }
472
473 /*
474 * XXX
475 * We only have a single file descriptor that we can return, not two. Return
476 * the same one for both files. Hopefully, the user is using it for locking
477 * and picked one to use at random.
478 */
479 int
__db_ndbm_dirfno(dbm)480 __db_ndbm_dirfno(dbm)
481 DBM *dbm;
482 {
483 return (dbm_pagfno(dbm));
484 }
485
486 int
__db_ndbm_pagfno(dbm)487 __db_ndbm_pagfno(dbm)
488 DBM *dbm;
489 {
490 DBC *dbc;
491 int fd;
492
493 dbc = (DBC *)dbm;
494
495 (void)dbc->dbp->fd(dbc->dbp, &fd);
496 return (fd);
497 }
498