1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: db185.c,v 12.13 2008/01/11 16:54:10 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12 13#ifndef lint 14static const char copyright[] = 15 "Copyright (c) 1996,2008 Oracle. All rights reserved.\n"; 16#endif 17 18#include "db185_int.h" 19 20static int db185_close __P((DB185 *)); 21static int db185_compare __P((DB *, const DBT *, const DBT *)); 22static int db185_del __P((const DB185 *, const DBT185 *, u_int)); 23static int db185_fd __P((const DB185 *)); 24static int db185_get __P((const DB185 *, const DBT185 *, DBT185 *, u_int)); 25static u_int32_t 26 db185_hash __P((DB *, const void *, u_int32_t)); 27static size_t db185_prefix __P((DB *, const DBT *, const DBT *)); 28static int db185_put __P((const DB185 *, DBT185 *, const DBT185 *, u_int)); 29static int db185_seq __P((const DB185 *, DBT185 *, DBT185 *, u_int)); 30static int db185_sync __P((const DB185 *, u_int)); 31 32/* 33 * EXTERN: #ifdef _DB185_INT_H_ 34 * EXTERN: DB185 *__db185_open 35 * EXTERN: __P((const char *, int, int, DBTYPE, const void *)); 36 * EXTERN: #else 37 * EXTERN: DB *__db185_open 38 * EXTERN: __P((const char *, int, int, DBTYPE, const void *)); 39 * EXTERN: #endif 40 */ 41DB185 * 42__db185_open(file, oflags, mode, type, openinfo) 43 const char *file; 44 int oflags, mode; 45 DBTYPE type; 46 const void *openinfo; 47{ 48 const BTREEINFO *bi; 49 const HASHINFO *hi; 50 const RECNOINFO *ri; 51 DB *dbp; 52 DB185 *db185p; 53 DB_FH *fhp; 54 int ret; 55 56 dbp = NULL; 57 db185p = NULL; 58 59 if ((ret = db_create(&dbp, NULL, 0)) != 0) 60 goto err; 61 62 if ((ret = __os_calloc(NULL, 1, sizeof(DB185), &db185p)) != 0) 63 goto err; 64 65 /* 66 * !!! 67 * The DBTYPE enum wasn't initialized in DB 185, so it's off-by-one 68 * from DB 2.0. 69 */ 70 switch (type) { 71 case 0: /* DB_BTREE */ 72 type = DB_BTREE; 73 if ((bi = openinfo) != NULL) { 74 if (bi->flags & ~R_DUP) 75 goto einval; 76 if (bi->flags & R_DUP) 77 (void)dbp->set_flags(dbp, DB_DUP); 78 if (bi->cachesize != 0) 79 (void)dbp->set_cachesize 80 (dbp, 0, bi->cachesize, 0); 81 if (bi->minkeypage != 0) 82 (void)dbp->set_bt_minkey(dbp, bi->minkeypage); 83 if (bi->psize != 0) 84 (void)dbp->set_pagesize(dbp, bi->psize); 85 if (bi->prefix != NULL) { 86 db185p->prefix = bi->prefix; 87 dbp->set_bt_prefix(dbp, db185_prefix); 88 } 89 if (bi->compare != NULL) { 90 db185p->compare = bi->compare; 91 dbp->set_bt_compare(dbp, db185_compare); 92 } 93 if (bi->lorder != 0) 94 dbp->set_lorder(dbp, bi->lorder); 95 } 96 break; 97 case 1: /* DB_HASH */ 98 type = DB_HASH; 99 if ((hi = openinfo) != NULL) { 100 if (hi->bsize != 0) 101 (void)dbp->set_pagesize(dbp, hi->bsize); 102 if (hi->ffactor != 0) 103 (void)dbp->set_h_ffactor(dbp, hi->ffactor); 104 if (hi->nelem != 0) 105 (void)dbp->set_h_nelem(dbp, hi->nelem); 106 if (hi->cachesize != 0) 107 (void)dbp->set_cachesize 108 (dbp, 0, hi->cachesize, 0); 109 if (hi->hash != NULL) { 110 db185p->hash = hi->hash; 111 (void)dbp->set_h_hash(dbp, db185_hash); 112 } 113 if (hi->lorder != 0) 114 dbp->set_lorder(dbp, hi->lorder); 115 } 116 117 break; 118 case 2: /* DB_RECNO */ 119 type = DB_RECNO; 120 121 /* DB 1.85 did renumbering by default. */ 122 (void)dbp->set_flags(dbp, DB_RENUMBER); 123 124 /* 125 * !!! 126 * The file name given to DB 1.85 recno is the name of the DB 127 * 2.0 backing file. If the file doesn't exist, create it if 128 * the user has the O_CREAT flag set, DB 1.85 did it for you, 129 * and DB 2.0 doesn't. 130 * 131 * !!! 132 * Setting the file name to NULL specifies that we're creating 133 * a temporary backing file, in DB 2.X. If we're opening the 134 * DB file read-only, change the flags to read-write, because 135 * temporary backing files cannot be opened read-only, and DB 136 * 2.X will return an error. We are cheating here -- if the 137 * application does a put on the database, it will succeed -- 138 * although that would be a stupid thing for the application 139 * to do. 140 * 141 * !!! 142 * Note, the file name in DB 1.85 was a const -- we don't do 143 * that in DB 2.0, so do that cast. 144 */ 145 if (file != NULL) { 146 if (oflags & O_CREAT && 147 __os_exists(NULL, file, NULL) != 0) 148 if (__os_openhandle(NULL, file, 149 oflags, mode, &fhp) == 0) 150 (void)__os_closehandle(NULL, fhp); 151 (void)dbp->set_re_source(dbp, file); 152 153 if (O_RDONLY) 154 oflags &= ~O_RDONLY; 155 oflags |= O_RDWR; 156 file = NULL; 157 } 158 159 /* 160 * !!! 161 * Set the O_CREAT flag in case the application didn't -- in DB 162 * 1.85 the backing file was the file being created and it may 163 * exist, but DB 2.X is creating a temporary Btree database and 164 * we need the create flag to do that. 165 */ 166 oflags |= O_CREAT; 167 168 if ((ri = openinfo) != NULL) { 169 /* 170 * !!! 171 * We can't support the bfname field. 172 */ 173#define BFMSG \ 174 "Berkeley DB: DB 1.85's recno bfname field is not supported.\n" 175 if (ri->bfname != NULL) { 176 dbp->errx(dbp, "%s", BFMSG); 177 goto einval; 178 } 179 180 if (ri->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT)) 181 goto einval; 182 if (ri->flags & R_FIXEDLEN) { 183 if (ri->bval != 0) 184 (void)dbp->set_re_pad(dbp, ri->bval); 185 if (ri->reclen != 0) 186 (void)dbp->set_re_len(dbp, ri->reclen); 187 } else 188 if (ri->bval != 0) 189 (void)dbp->set_re_delim(dbp, ri->bval); 190 191 /* 192 * !!! 193 * We ignore the R_NOKEY flag, but that's okay, it was 194 * only an optimization that was never implemented. 195 */ 196 if (ri->flags & R_SNAPSHOT) 197 (void)dbp->set_flags(dbp, DB_SNAPSHOT); 198 199 if (ri->cachesize != 0) 200 (void)dbp->set_cachesize 201 (dbp, 0, ri->cachesize, 0); 202 if (ri->psize != 0) 203 (void)dbp->set_pagesize(dbp, ri->psize); 204 if (ri->lorder != 0) 205 dbp->set_lorder(dbp, ri->lorder); 206 } 207 break; 208 default: 209 goto einval; 210 } 211 212 db185p->close = db185_close; 213 db185p->del = db185_del; 214 db185p->fd = db185_fd; 215 db185p->get = db185_get; 216 db185p->put = db185_put; 217 db185p->seq = db185_seq; 218 db185p->sync = db185_sync; 219 220 /* 221 * Store a reference so we can indirect from the DB 1.85 structure 222 * to the underlying DB structure, and vice-versa. This has to be 223 * done BEFORE the DB::open method call because the hash callback 224 * is exercised as part of hash database initialization. 225 */ 226 db185p->dbp = dbp; 227 dbp->api_internal = db185p; 228 229 /* Open the database. */ 230 if ((ret = dbp->open(dbp, NULL, 231 file, NULL, type, __db_openflags(oflags), mode)) != 0) 232 goto err; 233 234 /* Create the cursor used for sequential ops. */ 235 if ((ret = dbp->cursor(dbp, NULL, &((DB185 *)db185p)->dbc, 0)) != 0) 236 goto err; 237 238 return (db185p); 239 240einval: ret = EINVAL; 241 242err: if (db185p != NULL) 243 __os_free(NULL, db185p); 244 if (dbp != NULL) 245 (void)dbp->close(dbp, 0); 246 247 __os_set_errno(ret); 248 return (NULL); 249} 250 251static int 252db185_close(db185p) 253 DB185 *db185p; 254{ 255 DB *dbp; 256 int ret; 257 258 dbp = db185p->dbp; 259 260 ret = dbp->close(dbp, 0); 261 262 __os_free(NULL, db185p); 263 264 if (ret == 0) 265 return (0); 266 267 __os_set_errno(ret); 268 return (-1); 269} 270 271static int 272db185_del(db185p, key185, flags) 273 const DB185 *db185p; 274 const DBT185 *key185; 275 u_int flags; 276{ 277 DB *dbp; 278 DBT key; 279 int ret; 280 281 dbp = db185p->dbp; 282 283 memset(&key, 0, sizeof(key)); 284 key.data = key185->data; 285 key.size = key185->size; 286 287 if (flags & ~R_CURSOR) 288 goto einval; 289 if (flags & R_CURSOR) 290 ret = db185p->dbc->del(db185p->dbc, 0); 291 else 292 ret = dbp->del(dbp, NULL, &key, 0); 293 294 switch (ret) { 295 case 0: 296 return (0); 297 case DB_NOTFOUND: 298 return (1); 299 } 300 301 if (0) { 302einval: ret = EINVAL; 303 } 304 __os_set_errno(ret); 305 return (-1); 306} 307 308static int 309db185_fd(db185p) 310 const DB185 *db185p; 311{ 312 DB *dbp; 313 int fd, ret; 314 315 dbp = db185p->dbp; 316 317 if ((ret = dbp->fd(dbp, &fd)) == 0) 318 return (fd); 319 320 __os_set_errno(ret); 321 return (-1); 322} 323 324static int 325db185_get(db185p, key185, data185, flags) 326 const DB185 *db185p; 327 const DBT185 *key185; 328 DBT185 *data185; 329 u_int flags; 330{ 331 DB *dbp; 332 DBT key, data; 333 int ret; 334 335 dbp = db185p->dbp; 336 337 memset(&key, 0, sizeof(key)); 338 key.data = key185->data; 339 key.size = key185->size; 340 memset(&data, 0, sizeof(data)); 341 data.data = data185->data; 342 data.size = data185->size; 343 344 if (flags) 345 goto einval; 346 347 switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) { 348 case 0: 349 data185->data = data.data; 350 data185->size = data.size; 351 return (0); 352 case DB_NOTFOUND: 353 return (1); 354 } 355 356 if (0) { 357einval: ret = EINVAL; 358 } 359 __os_set_errno(ret); 360 return (-1); 361} 362 363static int 364db185_put(db185p, key185, data185, flags) 365 const DB185 *db185p; 366 DBT185 *key185; 367 const DBT185 *data185; 368 u_int flags; 369{ 370 DB *dbp; 371 DBC *dbcp_put; 372 DBT key, data; 373 int ret, t_ret; 374 375 dbp = db185p->dbp; 376 377 memset(&key, 0, sizeof(key)); 378 key.data = key185->data; 379 key.size = key185->size; 380 memset(&data, 0, sizeof(data)); 381 data.data = data185->data; 382 data.size = data185->size; 383 384 switch (flags) { 385 case 0: 386 ret = dbp->put(dbp, NULL, &key, &data, 0); 387 break; 388 case R_CURSOR: 389 ret = db185p->dbc->put(db185p->dbc, &key, &data, DB_CURRENT); 390 break; 391 case R_IAFTER: 392 case R_IBEFORE: 393 if (dbp->type != DB_RECNO) 394 goto einval; 395 396 if ((ret = dbp->cursor(dbp, NULL, &dbcp_put, 0)) != 0) 397 break; 398 if ((ret = 399 dbcp_put->get(dbcp_put, &key, &data, DB_SET)) == 0) { 400 memset(&data, 0, sizeof(data)); 401 data.data = data185->data; 402 data.size = data185->size; 403 ret = dbcp_put->put(dbcp_put, &key, &data, 404 flags == R_IAFTER ? DB_AFTER : DB_BEFORE); 405 } 406 if ((t_ret = dbcp_put->close(dbcp_put)) != 0 && ret == 0) 407 ret = t_ret; 408 break; 409 case R_NOOVERWRITE: 410 ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE); 411 break; 412 case R_SETCURSOR: 413 if (dbp->type != DB_BTREE && dbp->type != DB_RECNO) 414 goto einval; 415 416 if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) != 0) 417 break; 418 ret = 419 db185p->dbc->get(db185p->dbc, &key, &data, DB_SET_RANGE); 420 break; 421 default: 422 goto einval; 423 } 424 425 switch (ret) { 426 case 0: 427 key185->data = key.data; 428 key185->size = key.size; 429 return (0); 430 case DB_KEYEXIST: 431 return (1); 432 } 433 434 if (0) { 435einval: ret = EINVAL; 436 } 437 __os_set_errno(ret); 438 return (-1); 439} 440 441static int 442db185_seq(db185p, key185, data185, flags) 443 const DB185 *db185p; 444 DBT185 *key185, *data185; 445 u_int flags; 446{ 447 DB *dbp; 448 DBT key, data; 449 int ret; 450 451 dbp = db185p->dbp; 452 453 memset(&key, 0, sizeof(key)); 454 key.data = key185->data; 455 key.size = key185->size; 456 memset(&data, 0, sizeof(data)); 457 data.data = data185->data; 458 data.size = data185->size; 459 460 switch (flags) { 461 case R_CURSOR: 462 flags = DB_SET_RANGE; 463 break; 464 case R_FIRST: 465 flags = DB_FIRST; 466 break; 467 case R_LAST: 468 if (dbp->type != DB_BTREE && dbp->type != DB_RECNO) 469 goto einval; 470 flags = DB_LAST; 471 break; 472 case R_NEXT: 473 flags = DB_NEXT; 474 break; 475 case R_PREV: 476 if (dbp->type != DB_BTREE && dbp->type != DB_RECNO) 477 goto einval; 478 flags = DB_PREV; 479 break; 480 default: 481 goto einval; 482 } 483 switch (ret = db185p->dbc->get(db185p->dbc, &key, &data, flags)) { 484 case 0: 485 key185->data = key.data; 486 key185->size = key.size; 487 data185->data = data.data; 488 data185->size = data.size; 489 return (0); 490 case DB_NOTFOUND: 491 return (1); 492 } 493 494 if (0) { 495einval: ret = EINVAL; 496 } 497 __os_set_errno(ret); 498 return (-1); 499} 500 501static int 502db185_sync(db185p, flags) 503 const DB185 *db185p; 504 u_int flags; 505{ 506 DB *dbp; 507 int ret; 508 509 dbp = db185p->dbp; 510 511 switch (flags) { 512 case 0: 513 break; 514 case R_RECNOSYNC: 515 /* 516 * !!! 517 * We can't support the R_RECNOSYNC flag. 518 */ 519#define RSMSG \ 520 "Berkeley DB: DB 1.85's R_RECNOSYNC sync flag is not supported.\n" 521 dbp->errx(dbp, "%s", RSMSG); 522 /* FALLTHROUGH */ 523 default: 524 goto einval; 525 } 526 527 if ((ret = dbp->sync(dbp, 0)) == 0) 528 return (0); 529 530 if (0) { 531einval: ret = EINVAL; 532 } 533 __os_set_errno(ret); 534 return (-1); 535} 536 537/* 538 * db185_compare -- 539 * Cutout routine to call the user's Btree comparison function. 540 */ 541static int 542db185_compare(dbp, a, b) 543 DB *dbp; 544 const DBT *a, *b; 545{ 546 DBT185 a185, b185; 547 548 a185.data = a->data; 549 a185.size = a->size; 550 b185.data = b->data; 551 b185.size = b->size; 552 553 return (((DB185 *)dbp->api_internal)->compare(&a185, &b185)); 554} 555 556/* 557 * db185_prefix -- 558 * Cutout routine to call the user's Btree prefix function. 559 */ 560static size_t 561db185_prefix(dbp, a, b) 562 DB *dbp; 563 const DBT *a, *b; 564{ 565 DBT185 a185, b185; 566 567 a185.data = a->data; 568 a185.size = a->size; 569 b185.data = b->data; 570 b185.size = b->size; 571 572 return (((DB185 *)dbp->api_internal)->prefix(&a185, &b185)); 573} 574 575/* 576 * db185_hash -- 577 * Cutout routine to call the user's hash function. 578 */ 579static u_int32_t 580db185_hash(dbp, key, len) 581 DB *dbp; 582 const void *key; 583 u_int32_t len; 584{ 585 return (((DB185 *)dbp->api_internal)->hash(key, (size_t)len)); 586} 587