1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/crypto.h"
13#include "dbinc/db_page.h"
14#include "dbinc/btree.h"
15#include "dbinc/hash.h"
16#include "dbinc/lock.h"
17#include "dbinc/mp.h"
18#include "dbinc/qam.h"
19#include "dbinc/txn.h"
20
21#ifdef HAVE_RPC
22#ifdef HAVE_SYSTEM_INCLUDE_FILES
23#include <rpc/rpc.h>
24#endif
25#include "db_server.h"
26#include "dbinc_auto/rpc_client_ext.h"
27#endif
28
29static int  __db_get_byteswapped __P((DB *, int *));
30static int  __db_get_dbname __P((DB *, const char **, const char **));
31static DB_ENV *__db_get_env __P((DB *));
32static void __db_get_msgcall
33	      __P((DB *, void (**)(const DB_ENV *, const char *)));
34static DB_MPOOLFILE *__db_get_mpf __P((DB *));
35static int  __db_get_multiple __P((DB *));
36static int  __db_get_transactional __P((DB *));
37static int  __db_get_type __P((DB *, DBTYPE *dbtype));
38static int  __db_init __P((DB *, u_int32_t));
39static int  __db_get_alloc __P((DB *, void *(**)(size_t),
40		void *(**)(void *, size_t), void (**)(void *)));
41static int  __db_set_alloc __P((DB *, void *(*)(size_t),
42		void *(*)(void *, size_t), void (*)(void *)));
43static int  __db_get_append_recno __P((DB *,
44		int (**)(DB *, DBT *, db_recno_t)));
45static int  __db_set_append_recno __P((DB *, int (*)(DB *, DBT *, db_recno_t)));
46static int  __db_get_cachesize __P((DB *, u_int32_t *, u_int32_t *, int *));
47static int  __db_set_cachesize __P((DB *, u_int32_t, u_int32_t, int));
48static int  __db_get_create_dir __P((DB *, const char **));
49static int  __db_set_create_dir __P((DB *, const char *));
50static int  __db_get_dup_compare
51		__P((DB *, int (**)(DB *, const DBT *, const DBT *)));
52static int  __db_set_dup_compare
53		__P((DB *, int (*)(DB *, const DBT *, const DBT *)));
54static int  __db_get_encrypt_flags __P((DB *, u_int32_t *));
55static int  __db_set_encrypt __P((DB *, const char *, u_int32_t));
56static int  __db_get_feedback __P((DB *, void (**)(DB *, int, int)));
57static int  __db_set_feedback __P((DB *, void (*)(DB *, int, int)));
58static void __db_map_flags __P((DB *, u_int32_t *, u_int32_t *));
59static int  __db_get_pagesize __P((DB *, u_int32_t *));
60static int  __db_set_paniccall __P((DB *, void (*)(DB_ENV *, int)));
61static int  __db_set_priority __P((DB *, DB_CACHE_PRIORITY));
62static int  __db_get_priority __P((DB *, DB_CACHE_PRIORITY *));
63static void __db_get_errcall __P((DB *,
64	      void (**)(const DB_ENV *, const char *, const char *)));
65static void __db_set_errcall
66	      __P((DB *, void (*)(const DB_ENV *, const char *, const char *)));
67static void __db_get_errfile __P((DB *, FILE **));
68static void __db_set_errfile __P((DB *, FILE *));
69static void __db_get_errpfx __P((DB *, const char **));
70static void __db_set_errpfx __P((DB *, const char *));
71static void __db_set_msgcall
72	      __P((DB *, void (*)(const DB_ENV *, const char *)));
73static void __db_get_msgfile __P((DB *, FILE **));
74static void __db_set_msgfile __P((DB *, FILE *));
75static void __dbh_err __P((DB *, int, const char *, ...));
76static void __dbh_errx __P((DB *, const char *, ...));
77
78/*
79 * db_create --
80 *	DB constructor.
81 *
82 * EXTERN: int db_create __P((DB **, DB_ENV *, u_int32_t));
83 */
84int
85db_create(dbpp, dbenv, flags)
86	DB **dbpp;
87	DB_ENV *dbenv;
88	u_int32_t flags;
89{
90	DB_THREAD_INFO *ip;
91	ENV *env;
92	int ret;
93
94	ip = NULL;
95	env = dbenv == NULL ? NULL : dbenv->env;
96
97	/* Check for invalid function flags. */
98	if (flags != 0)
99		return (__db_ferr(env, "db_create", 0));
100
101	if (env != NULL)
102		ENV_ENTER(env, ip);
103	ret = __db_create_internal(dbpp, env, flags);
104	if (env != NULL)
105		ENV_LEAVE(env, ip);
106
107	return (ret);
108}
109
110/*
111 * __db_create_internal --
112 *	DB constructor internal routine.
113 *
114 * PUBLIC: int __db_create_internal  __P((DB **, ENV *, u_int32_t));
115 */
116int
117__db_create_internal(dbpp, env, flags)
118	DB **dbpp;
119	ENV *env;
120	u_int32_t flags;
121{
122	DB *dbp;
123	DB_ENV *dbenv;
124	DB_REP *db_rep;
125	int ret;
126
127	*dbpp = NULL;
128
129	/* If we don't have an environment yet, allocate a local one. */
130	if (env == NULL) {
131		if ((ret = db_env_create(&dbenv, 0)) != 0)
132			return (ret);
133		env = dbenv->env;
134		F_SET(env, ENV_DBLOCAL);
135	} else
136		dbenv = env->dbenv;
137
138	/* Allocate and initialize the DB handle. */
139	if ((ret = __os_calloc(env, 1, sizeof(*dbp), &dbp)) != 0)
140		goto err;
141
142	dbp->dbenv = env->dbenv;
143	dbp->env = env;
144	if ((ret = __db_init(dbp, flags)) != 0)
145		goto err;
146
147	MUTEX_LOCK(env, env->mtx_dblist);
148	++env->db_ref;
149	MUTEX_UNLOCK(env, env->mtx_dblist);
150
151	/*
152	 * Set the replication timestamp; it's 0 if we're not in a replicated
153	 * environment.  Don't acquire a lock to read the value, even though
154	 * it's opaque: all we check later is value equality, nothing else.
155	 */
156	dbp->timestamp = REP_ON(env) ?
157	    ((REGENV *)env->reginfo->primary)->rep_timestamp : 0;
158	/*
159	 * Set the replication generation number for fid management; valid
160	 * replication generations start at 1.  Don't acquire a lock to
161	 * read the value.  All we check later is value equality.
162	 */
163	db_rep = env->rep_handle;
164	dbp->fid_gen = REP_ON(env) ? ((REP *)db_rep->region)->gen : 0;
165
166	/* If not RPC, open a backing DB_MPOOLFILE handle in the memory pool. */
167	if (!RPC_ON(dbenv) && (ret = __memp_fcreate(env, &dbp->mpf)) != 0)
168		goto err;
169
170	dbp->type = DB_UNKNOWN;
171
172	*dbpp = dbp;
173	return (0);
174
175err:	if (dbp != NULL) {
176		if (dbp->mpf != NULL)
177			(void)__memp_fclose(dbp->mpf, 0);
178		__os_free(env, dbp);
179	}
180
181	if (F_ISSET(env, ENV_DBLOCAL))
182		(void)__env_close(dbp->dbenv, 0);
183
184	return (ret);
185}
186
187/*
188 * __db_init --
189 *	Initialize a DB structure.
190 */
191static int
192__db_init(dbp, flags)
193	DB *dbp;
194	u_int32_t flags;
195{
196	int ret;
197
198	dbp->locker = NULL;
199	LOCK_INIT(dbp->handle_lock);
200
201	TAILQ_INIT(&dbp->free_queue);
202	TAILQ_INIT(&dbp->active_queue);
203	TAILQ_INIT(&dbp->join_queue);
204	LIST_INIT(&dbp->s_secondaries);
205
206	FLD_SET(dbp->am_ok,
207	    DB_OK_BTREE | DB_OK_HASH | DB_OK_QUEUE | DB_OK_RECNO);
208
209	/* DB PUBLIC HANDLE LIST BEGIN */
210	dbp->associate = __db_associate_pp;
211	dbp->associate_foreign = __db_associate_foreign_pp;
212	dbp->close = __db_close_pp;
213	dbp->compact = __db_compact_pp;
214	dbp->cursor = __db_cursor_pp;
215	dbp->del = __db_del_pp;
216	dbp->dump = __db_dump_pp;
217	dbp->err = __dbh_err;
218	dbp->errx = __dbh_errx;
219	dbp->exists = __db_exists;
220	dbp->fd = __db_fd_pp;
221	dbp->get = __db_get_pp;
222	dbp->get_alloc = __db_get_alloc;
223	dbp->get_append_recno = __db_get_append_recno;
224	dbp->get_byteswapped = __db_get_byteswapped;
225	dbp->get_cachesize = __db_get_cachesize;
226	dbp->get_create_dir = __db_get_create_dir;
227	dbp->get_dbname = __db_get_dbname;
228	dbp->get_dup_compare = __db_get_dup_compare;
229	dbp->get_encrypt_flags = __db_get_encrypt_flags;
230	dbp->get_env = __db_get_env;
231	dbp->get_errcall = __db_get_errcall;
232	dbp->get_errfile = __db_get_errfile;
233	dbp->get_errpfx = __db_get_errpfx;
234	dbp->get_feedback = __db_get_feedback;
235	dbp->get_flags = __db_get_flags;
236	dbp->get_lorder = __db_get_lorder;
237	dbp->get_mpf = __db_get_mpf;
238	dbp->get_msgcall = __db_get_msgcall;
239	dbp->get_msgfile = __db_get_msgfile;
240	dbp->get_multiple = __db_get_multiple;
241	dbp->get_open_flags = __db_get_open_flags;
242	dbp->get_partition_dirs = __partition_get_dirs;
243	dbp->get_partition_callback = __partition_get_callback;
244	dbp->get_partition_keys = __partition_get_keys;
245	dbp->get_pagesize = __db_get_pagesize;
246	dbp->get_priority = __db_get_priority;
247	dbp->get_transactional = __db_get_transactional;
248	dbp->get_type = __db_get_type;
249	dbp->join = __db_join_pp;
250	dbp->key_range = __db_key_range_pp;
251	dbp->open = __db_open_pp;
252	dbp->pget = __db_pget_pp;
253	dbp->put = __db_put_pp;
254	dbp->remove = __db_remove_pp;
255	dbp->rename = __db_rename_pp;
256	dbp->set_alloc = __db_set_alloc;
257	dbp->set_append_recno = __db_set_append_recno;
258	dbp->set_cachesize = __db_set_cachesize;
259	dbp->set_create_dir = __db_set_create_dir;
260	dbp->set_dup_compare = __db_set_dup_compare;
261	dbp->set_encrypt = __db_set_encrypt;
262	dbp->set_errcall = __db_set_errcall;
263	dbp->set_errfile = __db_set_errfile;
264	dbp->set_errpfx = __db_set_errpfx;
265	dbp->set_feedback = __db_set_feedback;
266	dbp->set_flags = __db_set_flags;
267	dbp->set_lorder = __db_set_lorder;
268	dbp->set_msgcall = __db_set_msgcall;
269	dbp->set_msgfile = __db_set_msgfile;
270	dbp->set_pagesize = __db_set_pagesize;
271	dbp->set_paniccall = __db_set_paniccall;
272	dbp->set_partition = __partition_set;
273	dbp->set_partition_dirs = __partition_set_dirs;
274	dbp->set_priority = __db_set_priority;
275	dbp->sort_multiple = __db_sort_multiple;
276	dbp->stat = __db_stat_pp;
277	dbp->stat_print = __db_stat_print_pp;
278	dbp->sync = __db_sync_pp;
279	dbp->truncate = __db_truncate_pp;
280	dbp->upgrade = __db_upgrade_pp;
281	dbp->verify = __db_verify_pp;
282	/* DB PUBLIC HANDLE LIST END */
283
284					/* Access method specific. */
285	if ((ret = __bam_db_create(dbp)) != 0)
286		return (ret);
287	if ((ret = __ham_db_create(dbp)) != 0)
288		return (ret);
289	if ((ret = __qam_db_create(dbp)) != 0)
290		return (ret);
291
292#ifdef HAVE_RPC
293	/*
294	 * RPC specific: must be last, as we replace methods set by the
295	 * access methods.
296	 */
297	if (RPC_ON(dbp->dbenv)) {
298		__dbcl_dbp_init(dbp);
299		/*
300		 * !!!
301		 * We wrap the DB->open method for RPC, and the rpc.src file
302		 * can't handle that.
303		 */
304		dbp->open = __dbcl_db_open_wrap;
305		if ((ret = __dbcl_db_create(dbp, dbp->dbenv, flags)) != 0)
306			return (ret);
307	}
308#else
309	COMPQUIET(flags, 0);
310#endif
311
312	return (0);
313}
314
315/*
316 * __dbh_am_chk --
317 *	Error if an unreasonable method is called.
318 *
319 * PUBLIC: int __dbh_am_chk __P((DB *, u_int32_t));
320 */
321int
322__dbh_am_chk(dbp, flags)
323	DB *dbp;
324	u_int32_t flags;
325{
326	/*
327	 * We start out allowing any access methods to be called, and as the
328	 * application calls the methods the options become restricted.  The
329	 * idea is to quit as soon as an illegal method combination is called.
330	 */
331	if ((LF_ISSET(DB_OK_BTREE) && FLD_ISSET(dbp->am_ok, DB_OK_BTREE)) ||
332	    (LF_ISSET(DB_OK_HASH) && FLD_ISSET(dbp->am_ok, DB_OK_HASH)) ||
333	    (LF_ISSET(DB_OK_QUEUE) && FLD_ISSET(dbp->am_ok, DB_OK_QUEUE)) ||
334	    (LF_ISSET(DB_OK_RECNO) && FLD_ISSET(dbp->am_ok, DB_OK_RECNO))) {
335		FLD_CLR(dbp->am_ok, ~flags);
336		return (0);
337	}
338
339	__db_errx(dbp->env,
340    "call implies an access method which is inconsistent with previous calls");
341	return (EINVAL);
342}
343
344/*
345 * __dbh_err --
346 *	Db.err method.
347 */
348static void
349#ifdef STDC_HEADERS
350__dbh_err(DB *dbp, int error, const char *fmt, ...)
351#else
352__dbh_err(dbp, error, fmt, va_alist)
353	DB *dbp;
354	int error;
355	const char *fmt;
356	va_dcl
357#endif
358{
359	/* Message with error string, to stderr by default. */
360	DB_REAL_ERR(dbp->dbenv, error, DB_ERROR_SET, 1, fmt);
361}
362
363/*
364 * __dbh_errx --
365 *	Db.errx method.
366 */
367static void
368#ifdef STDC_HEADERS
369__dbh_errx(DB *dbp, const char *fmt, ...)
370#else
371__dbh_errx(dbp, fmt, va_alist)
372	DB *dbp;
373	const char *fmt;
374	va_dcl
375#endif
376{
377	/* Message without error string, to stderr by default. */
378	DB_REAL_ERR(dbp->dbenv, 0, DB_ERROR_NOT_SET, 1, fmt);
379}
380
381/*
382 * __db_get_byteswapped --
383 *	Return if database requires byte swapping.
384 */
385static int
386__db_get_byteswapped(dbp, isswapped)
387	DB *dbp;
388	int *isswapped;
389{
390	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_byteswapped");
391
392	*isswapped = F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0;
393	return (0);
394}
395
396/*
397 * __db_get_dbname --
398 *	Get the name of the database as passed to DB->open.
399 */
400static int
401__db_get_dbname(dbp, fnamep, dnamep)
402	DB *dbp;
403	const char **fnamep, **dnamep;
404{
405	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_dbname");
406
407	if (fnamep != NULL)
408		*fnamep = dbp->fname;
409	if (dnamep != NULL)
410		*dnamep = dbp->dname;
411	return (0);
412}
413
414/*
415 * __db_get_env --
416 *	Get the DB_ENV handle that was passed to db_create.
417 */
418static DB_ENV *
419__db_get_env(dbp)
420	DB *dbp;
421{
422	return (dbp->dbenv);
423}
424
425/*
426 * __db_get_mpf --
427 *	Get the underlying DB_MPOOLFILE handle.
428 */
429static DB_MPOOLFILE *
430__db_get_mpf(dbp)
431	DB *dbp;
432{
433	return (dbp->mpf);
434}
435
436/*
437 * get_multiple --
438 *	Return whether this DB handle references a physical file with multiple
439 *	databases.
440 */
441static int
442__db_get_multiple(dbp)
443	DB *dbp;
444{
445	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_multiple");
446
447	/*
448	 * Only return TRUE if the handle is for the master database, not for
449	 * any subdatabase in the physical file.  If it's a Btree, with the
450	 * subdatabases flag set, and the meta-data page has the right value,
451	 * return TRUE.  (We don't need to check it's a Btree, I suppose, but
452	 * it doesn't hurt.)
453	 */
454	return (dbp->type == DB_BTREE &&
455	    F_ISSET(dbp, DB_AM_SUBDB) &&
456	    dbp->meta_pgno == PGNO_BASE_MD ? 1 : 0);
457}
458
459/*
460 * get_transactional --
461 *	Return whether this database was created in a transaction.
462 */
463static int
464__db_get_transactional(dbp)
465	DB *dbp;
466{
467	return (F_ISSET(dbp, DB_AM_TXN) ? 1 : 0);
468}
469
470/*
471 * __db_get_type --
472 *	Return type of underlying database.
473 */
474static int
475__db_get_type(dbp, dbtype)
476	DB *dbp;
477	DBTYPE *dbtype;
478{
479	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_type");
480
481	*dbtype = dbp->type;
482	return (0);
483}
484
485/*
486 * __db_get_append_recno --
487 *	Get record number append routine.
488 */
489static int
490__db_get_append_recno(dbp, funcp)
491	DB *dbp;
492	int (**funcp) __P((DB *, DBT *, db_recno_t));
493{
494	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
495	if (funcp)
496		*funcp = dbp->db_append_recno;
497
498	return (0);
499}
500/*
501 * __db_set_append_recno --
502 *	Set record number append routine.
503 */
504static int
505__db_set_append_recno(dbp, func)
506	DB *dbp;
507	int (*func) __P((DB *, DBT *, db_recno_t));
508{
509	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_append_recno");
510	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
511
512	dbp->db_append_recno = func;
513
514	return (0);
515}
516
517/*
518 * __db_get_cachesize --
519 *	Get underlying cache size.
520 */
521static int
522__db_get_cachesize(dbp, cache_gbytesp, cache_bytesp, ncachep)
523	DB *dbp;
524	u_int32_t *cache_gbytesp, *cache_bytesp;
525	int *ncachep;
526{
527	DB_ILLEGAL_IN_ENV(dbp, "DB->get_cachesize");
528
529	return (__memp_get_cachesize(dbp->dbenv,
530	    cache_gbytesp, cache_bytesp, ncachep));
531}
532
533/*
534 * __db_set_cachesize --
535 *	Set underlying cache size.
536 */
537static int
538__db_set_cachesize(dbp, cache_gbytes, cache_bytes, ncache)
539	DB *dbp;
540	u_int32_t cache_gbytes, cache_bytes;
541	int ncache;
542{
543	DB_ILLEGAL_IN_ENV(dbp, "DB->set_cachesize");
544	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_cachesize");
545
546	return (__memp_set_cachesize(
547	    dbp->dbenv, cache_gbytes, cache_bytes, ncache));
548}
549
550static int
551__db_set_create_dir(dbp, dir)
552	DB *dbp;
553	const char *dir;
554{
555	DB_ENV *dbenv;
556	int i;
557
558	dbenv = dbp->dbenv;
559
560	for (i = 0; i < dbenv->data_next; i++)
561		if (strcmp(dir, dbenv->db_data_dir[i]) == 0)
562			break;
563
564	if (i == dbenv->data_next) {
565		__db_errx(dbp->env,
566		     "Directory %s not in environment list.", dir);
567		return (EINVAL);
568	}
569
570	dbp->dirname = dbenv->db_data_dir[i];
571	return (0);
572}
573
574static int
575__db_get_create_dir(dbp, dirp)
576	DB *dbp;
577	const char **dirp;
578{
579	*dirp = dbp->dirname;
580	return (0);
581}
582
583/*
584 * __db_get_dup_compare --
585 *	Get duplicate comparison routine.
586 */
587static int
588__db_get_dup_compare(dbp, funcp)
589	DB *dbp;
590	int (**funcp) __P((DB *, const DBT *, const DBT *));
591{
592
593	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
594
595	if (funcp != NULL) {
596#ifdef HAVE_COMPRESSION
597		if (DB_IS_COMPRESSED(dbp)) {
598			*funcp =
599			     ((BTREE *)dbp->bt_internal)->compress_dup_compare;
600		} else
601#endif
602			*funcp = dbp->dup_compare;
603	}
604
605	return (0);
606}
607
608/*
609 * __db_set_dup_compare --
610 *	Set duplicate comparison routine.
611 */
612static int
613__db_set_dup_compare(dbp, func)
614	DB *dbp;
615	int (*func) __P((DB *, const DBT *, const DBT *));
616{
617	int ret;
618
619	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_dup_compare");
620	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
621
622	if ((ret = __db_set_flags(dbp, DB_DUPSORT)) != 0)
623		return (ret);
624
625#ifdef HAVE_COMPRESSION
626	if (DB_IS_COMPRESSED(dbp)) {
627		dbp->dup_compare = __bam_compress_dupcmp;
628		((BTREE *)dbp->bt_internal)->compress_dup_compare = func;
629	} else
630#endif
631		dbp->dup_compare = func;
632
633	return (0);
634}
635
636/*
637 * __db_get_encrypt_flags --
638 */
639static int
640__db_get_encrypt_flags(dbp, flagsp)
641	DB *dbp;
642	u_int32_t *flagsp;
643{
644	DB_ILLEGAL_IN_ENV(dbp, "DB->get_encrypt_flags");
645
646	return (__env_get_encrypt_flags(dbp->dbenv, flagsp));
647}
648
649/*
650 * __db_set_encrypt --
651 *	Set database passwd.
652 */
653static int
654__db_set_encrypt(dbp, passwd, flags)
655	DB *dbp;
656	const char *passwd;
657	u_int32_t flags;
658{
659	DB_CIPHER *db_cipher;
660	int ret;
661
662	DB_ILLEGAL_IN_ENV(dbp, "DB->set_encrypt");
663	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_encrypt");
664
665	if ((ret = __env_set_encrypt(dbp->dbenv, passwd, flags)) != 0)
666		return (ret);
667
668	/*
669	 * In a real env, this gets initialized with the region.  In a local
670	 * env, we must do it here.
671	 */
672	db_cipher = dbp->env->crypto_handle;
673	if (!F_ISSET(db_cipher, CIPHER_ANY) &&
674	    (ret = db_cipher->init(dbp->env, db_cipher)) != 0)
675		return (ret);
676
677	return (__db_set_flags(dbp, DB_ENCRYPT));
678}
679
680static void
681__db_get_errcall(dbp, errcallp)
682	DB *dbp;
683	void (**errcallp) __P((const DB_ENV *, const char *, const char *));
684{
685	__env_get_errcall(dbp->dbenv, errcallp);
686}
687
688static void
689__db_set_errcall(dbp, errcall)
690	DB *dbp;
691	void (*errcall) __P((const DB_ENV *, const char *, const char *));
692{
693	__env_set_errcall(dbp->dbenv, errcall);
694}
695
696static void
697__db_get_errfile(dbp, errfilep)
698	DB *dbp;
699	FILE **errfilep;
700{
701	__env_get_errfile(dbp->dbenv, errfilep);
702}
703
704static void
705__db_set_errfile(dbp, errfile)
706	DB *dbp;
707	FILE *errfile;
708{
709	__env_set_errfile(dbp->dbenv, errfile);
710}
711
712static void
713__db_get_errpfx(dbp, errpfxp)
714	DB *dbp;
715	const char **errpfxp;
716{
717	__env_get_errpfx(dbp->dbenv, errpfxp);
718}
719
720static void
721__db_set_errpfx(dbp, errpfx)
722	DB *dbp;
723	const char *errpfx;
724{
725	__env_set_errpfx(dbp->dbenv, errpfx);
726}
727
728static int
729__db_get_feedback(dbp, feedbackp)
730	DB *dbp;
731	void (**feedbackp) __P((DB *, int, int));
732{
733	if (feedbackp != NULL)
734		*feedbackp = dbp->db_feedback;
735	return (0);
736}
737
738static int
739__db_set_feedback(dbp, feedback)
740	DB *dbp;
741	void (*feedback) __P((DB *, int, int));
742{
743	dbp->db_feedback = feedback;
744	return (0);
745}
746
747/*
748 * __db_map_flags --
749 *	Maps between public and internal flag values.
750 *      This function doesn't check for validity, so it can't fail.
751 */
752static void
753__db_map_flags(dbp, inflagsp, outflagsp)
754	DB *dbp;
755	u_int32_t *inflagsp, *outflagsp;
756{
757	COMPQUIET(dbp, NULL);
758
759	if (FLD_ISSET(*inflagsp, DB_CHKSUM)) {
760		FLD_SET(*outflagsp, DB_AM_CHKSUM);
761		FLD_CLR(*inflagsp, DB_CHKSUM);
762	}
763	if (FLD_ISSET(*inflagsp, DB_ENCRYPT)) {
764		FLD_SET(*outflagsp, DB_AM_ENCRYPT | DB_AM_CHKSUM);
765		FLD_CLR(*inflagsp, DB_ENCRYPT);
766	}
767	if (FLD_ISSET(*inflagsp, DB_TXN_NOT_DURABLE)) {
768		FLD_SET(*outflagsp, DB_AM_NOT_DURABLE);
769		FLD_CLR(*inflagsp, DB_TXN_NOT_DURABLE);
770	}
771}
772
773/*
774 * __db_get_flags --
775 *	The DB->get_flags method.
776 *
777 * PUBLIC: int __db_get_flags __P((DB *, u_int32_t *));
778 */
779int
780__db_get_flags(dbp, flagsp)
781	DB *dbp;
782	u_int32_t *flagsp;
783{
784	static const u_int32_t db_flags[] = {
785		DB_CHKSUM,
786		DB_DUP,
787		DB_DUPSORT,
788		DB_ENCRYPT,
789#ifdef HAVE_QUEUE
790		DB_INORDER,
791#endif
792		DB_RECNUM,
793		DB_RENUMBER,
794		DB_REVSPLITOFF,
795		DB_SNAPSHOT,
796		DB_TXN_NOT_DURABLE,
797		0
798	};
799	u_int32_t f, flags, mapped_flag;
800	int i;
801
802	flags = 0;
803	for (i = 0; (f = db_flags[i]) != 0; i++) {
804		mapped_flag = 0;
805		__db_map_flags(dbp, &f, &mapped_flag);
806		__bam_map_flags(dbp, &f, &mapped_flag);
807		__ram_map_flags(dbp, &f, &mapped_flag);
808#ifdef HAVE_QUEUE
809		__qam_map_flags(dbp, &f, &mapped_flag);
810#endif
811		DB_ASSERT(dbp->env, f == 0);
812		if (F_ISSET(dbp, mapped_flag) == mapped_flag)
813			LF_SET(db_flags[i]);
814	}
815
816	*flagsp = flags;
817	return (0);
818}
819
820/*
821 * __db_set_flags --
822 *	DB->set_flags.
823 *
824 * PUBLIC: int  __db_set_flags __P((DB *, u_int32_t));
825 */
826int
827__db_set_flags(dbp, flags)
828	DB *dbp;
829	u_int32_t flags;
830{
831	ENV *env;
832	int ret;
833
834	env = dbp->env;
835
836	if (LF_ISSET(DB_ENCRYPT) && !CRYPTO_ON(env)) {
837		__db_errx(env,
838		    "Database environment not configured for encryption");
839		return (EINVAL);
840	}
841	if (LF_ISSET(DB_TXN_NOT_DURABLE))
842		ENV_REQUIRES_CONFIG(env,
843		    env->tx_handle, "DB_NOT_DURABLE", DB_INIT_TXN);
844
845	__db_map_flags(dbp, &flags, &dbp->flags);
846
847	if ((ret = __bam_set_flags(dbp, &flags)) != 0)
848		return (ret);
849	if ((ret = __ram_set_flags(dbp, &flags)) != 0)
850		return (ret);
851#ifdef HAVE_QUEUE
852	if ((ret = __qam_set_flags(dbp, &flags)) != 0)
853		return (ret);
854#endif
855
856	return (flags == 0 ? 0 : __db_ferr(env, "DB->set_flags", 0));
857}
858
859/*
860 * __db_get_lorder --
861 *	Get whether lorder is swapped or not.
862 *
863 * PUBLIC: int  __db_get_lorder __P((DB *, int *));
864 */
865int
866__db_get_lorder(dbp, db_lorderp)
867	DB *dbp;
868	int *db_lorderp;
869{
870	int ret;
871
872	/* Flag if the specified byte order requires swapping. */
873	switch (ret = __db_byteorder(dbp->env, 1234)) {
874	case 0:
875		*db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 4321 : 1234;
876		break;
877	case DB_SWAPBYTES:
878		*db_lorderp = F_ISSET(dbp, DB_AM_SWAP) ? 1234 : 4321;
879		break;
880	default:
881		return (ret);
882		/* NOTREACHED */
883	}
884
885	return (0);
886}
887
888/*
889 * __db_set_lorder --
890 *	Set whether lorder is swapped or not.
891 *
892 * PUBLIC: int  __db_set_lorder __P((DB *, int));
893 */
894int
895__db_set_lorder(dbp, db_lorder)
896	DB *dbp;
897	int db_lorder;
898{
899	int ret;
900
901	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_lorder");
902
903	/* Flag if the specified byte order requires swapping. */
904	switch (ret = __db_byteorder(dbp->env, db_lorder)) {
905	case 0:
906		F_CLR(dbp, DB_AM_SWAP);
907		break;
908	case DB_SWAPBYTES:
909		F_SET(dbp, DB_AM_SWAP);
910		break;
911	default:
912		return (ret);
913		/* NOTREACHED */
914	}
915	return (0);
916}
917
918static int
919__db_get_alloc(dbp, mal_funcp, real_funcp, free_funcp)
920	DB *dbp;
921	void *(**mal_funcp) __P((size_t));
922	void *(**real_funcp) __P((void *, size_t));
923	void (**free_funcp) __P((void *));
924{
925	DB_ILLEGAL_IN_ENV(dbp, "DB->get_alloc");
926
927	return (__env_get_alloc(dbp->dbenv, mal_funcp,
928	    real_funcp, free_funcp));
929}
930
931static int
932__db_set_alloc(dbp, mal_func, real_func, free_func)
933	DB *dbp;
934	void *(*mal_func) __P((size_t));
935	void *(*real_func) __P((void *, size_t));
936	void (*free_func) __P((void *));
937{
938	DB_ILLEGAL_IN_ENV(dbp, "DB->set_alloc");
939	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_alloc");
940
941	return (__env_set_alloc(dbp->dbenv, mal_func, real_func, free_func));
942}
943
944static void
945__db_get_msgcall(dbp, msgcallp)
946	DB *dbp;
947	void (**msgcallp) __P((const DB_ENV *, const char *));
948{
949	__env_get_msgcall(dbp->dbenv, msgcallp);
950}
951
952static void
953__db_set_msgcall(dbp, msgcall)
954	DB *dbp;
955	void (*msgcall) __P((const DB_ENV *, const char *));
956{
957	__env_set_msgcall(dbp->dbenv, msgcall);
958}
959
960static void
961__db_get_msgfile(dbp, msgfilep)
962	DB *dbp;
963	FILE **msgfilep;
964{
965	__env_get_msgfile(dbp->dbenv, msgfilep);
966}
967
968static void
969__db_set_msgfile(dbp, msgfile)
970	DB *dbp;
971	FILE *msgfile;
972{
973	__env_set_msgfile(dbp->dbenv, msgfile);
974}
975
976static int
977__db_get_pagesize(dbp, db_pagesizep)
978	DB *dbp;
979	u_int32_t *db_pagesizep;
980{
981	*db_pagesizep = dbp->pgsize;
982	return (0);
983}
984
985/*
986 * __db_set_pagesize --
987 *	DB->set_pagesize
988 *
989 * PUBLIC: int  __db_set_pagesize __P((DB *, u_int32_t));
990 */
991int
992__db_set_pagesize(dbp, db_pagesize)
993	DB *dbp;
994	u_int32_t db_pagesize;
995{
996	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_pagesize");
997
998	if (db_pagesize < DB_MIN_PGSIZE) {
999		__db_errx(dbp->env, "page sizes may not be smaller than %lu",
1000		    (u_long)DB_MIN_PGSIZE);
1001		return (EINVAL);
1002	}
1003	if (db_pagesize > DB_MAX_PGSIZE) {
1004		__db_errx(dbp->env, "page sizes may not be larger than %lu",
1005		    (u_long)DB_MAX_PGSIZE);
1006		return (EINVAL);
1007	}
1008
1009	/*
1010	 * We don't want anything that's not a power-of-2, as we rely on that
1011	 * for alignment of various types on the pages.
1012	 */
1013	if (!POWER_OF_TWO(db_pagesize)) {
1014		__db_errx(dbp->env, "page sizes must be a power-of-2");
1015		return (EINVAL);
1016	}
1017
1018	/*
1019	 * XXX
1020	 * Should we be checking for a page size that's not a multiple of 512,
1021	 * so that we never try and write less than a disk sector?
1022	 */
1023	dbp->pgsize = db_pagesize;
1024
1025	return (0);
1026}
1027
1028static int
1029__db_set_paniccall(dbp, paniccall)
1030	DB *dbp;
1031	void (*paniccall) __P((DB_ENV *, int));
1032{
1033	return (__env_set_paniccall(dbp->dbenv, paniccall));
1034}
1035
1036static int
1037__db_set_priority(dbp, priority)
1038	DB *dbp;
1039	DB_CACHE_PRIORITY priority;
1040{
1041	dbp->priority = priority;
1042	return (0);
1043}
1044
1045static int
1046__db_get_priority(dbp, priority)
1047	DB *dbp;
1048	DB_CACHE_PRIORITY *priority;
1049{
1050	*priority = dbp->priority;
1051	return (0);
1052}
1053