1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 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: dbm.c,v 12.14 2008/01/11 20:49:58 bostic Exp $ 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 */ 82static DBM *__cur_db; 83 84static void __db_no_open __P((void)); 85 86int 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 99int 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 109datum 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 124datum 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 138datum 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 155int 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 166int 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 177static 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 */ 193DBM * 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 */ 251void 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 */ 267datum 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 */ 308datum 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 */ 343datum 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 */ 378int 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 */ 409int 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 436int 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 447int 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 */ 464int 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 */ 481int 482__db_ndbm_dirfno(dbm) 483 DBM *dbm; 484{ 485 return (dbm_pagfno(dbm)); 486} 487 488int 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} 500