~vlad-lesin/percona-server/mysql-5.0.33-original

« back to all changes in this revision

Viewing changes to bdb/db/db_open.c

  • Committer: Vlad Lesin
  • Date: 2012-07-31 09:21:34 UTC
  • Revision ID: vladislav.lesin@percona.com-20120731092134-zfodx022b7992wsi
VirginĀ 5.0.33

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * See the file LICENSE for redistribution information.
 
3
 *
 
4
 * Copyright (c) 1996-2002
 
5
 *      Sleepycat Software.  All rights reserved.
 
6
 */
 
7
 
 
8
#include "db_config.h"
 
9
 
 
10
#ifndef lint
 
11
static const char revid[] = "$Id: db_open.c,v 11.215 2002/08/15 15:27:52 bostic Exp $";
 
12
#endif /* not lint */
 
13
 
 
14
#ifndef NO_SYSTEM_INCLUDES
 
15
#include <sys/types.h>
 
16
 
 
17
#include <stddef.h>
 
18
#include <stdlib.h>
 
19
#include <string.h>
 
20
#endif
 
21
 
 
22
#include "db_int.h"
 
23
#include "dbinc/db_page.h"
 
24
#include "dbinc/db_shash.h"
 
25
#include "dbinc/db_swap.h"
 
26
#include "dbinc/btree.h"
 
27
#include "dbinc/crypto.h"
 
28
#include "dbinc/hmac.h"
 
29
#include "dbinc/fop.h"
 
30
#include "dbinc/hash.h"
 
31
#include "dbinc/lock.h"
 
32
#include "dbinc/log.h"
 
33
#include "dbinc/qam.h"
 
34
#include "dbinc/txn.h"
 
35
 
 
36
static int __db_openchk __P((DB *,
 
37
    DB_TXN *, const char *, const char *, DBTYPE, u_int32_t));
 
38
 
 
39
/*
 
40
 * __db_open --
 
41
 *      Main library interface to the DB access methods.
 
42
 *
 
43
 * PUBLIC: int __db_open __P((DB *, DB_TXN *,
 
44
 * PUBLIC:     const char *, const char *, DBTYPE, u_int32_t, int));
 
45
 */
 
46
int
 
47
__db_open(dbp, txn, name, subdb, type, flags, mode)
 
48
        DB *dbp;
 
49
        DB_TXN *txn;
 
50
        const char *name, *subdb;
 
51
        DBTYPE type;
 
52
        u_int32_t flags;
 
53
        int mode;
 
54
{
 
55
        DB_ENV *dbenv;
 
56
        int remove_master, remove_me, ret, t_ret, txn_local;
 
57
 
 
58
        dbenv = dbp->dbenv;
 
59
        remove_me = remove_master = txn_local = 0;
 
60
 
 
61
        PANIC_CHECK(dbenv);
 
62
 
 
63
        if ((ret = __db_openchk(dbp, txn, name, subdb, type, flags)) != 0)
 
64
                return (ret);
 
65
 
 
66
        /*
 
67
         * Create local transaction as necessary, check for consistent
 
68
         * transaction usage.
 
69
         */
 
70
        if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
 
71
                if ((ret = __db_txn_auto(dbp, &txn)) != 0)
 
72
                        return (ret);
 
73
                txn_local = 1;
 
74
        } else
 
75
                if (txn != NULL && !TXN_ON(dbenv))
 
76
                        return (__db_not_txn_env(dbenv));
 
77
 
 
78
        /*
 
79
         * If the environment was configured with threads, the DB handle
 
80
         * must also be free-threaded, so we force the DB_THREAD flag on.
 
81
         * (See SR #2033 for why this is a requirement--recovery needs
 
82
         * to be able to grab a dbp using __db_fileid_to_dbp, and it has
 
83
         * no way of knowing which dbp goes with which thread, so whichever
 
84
         * one it finds has to be usable in any of them.)
 
85
         */
 
86
        if (F_ISSET(dbenv, DB_ENV_THREAD))
 
87
                LF_SET(DB_THREAD);
 
88
 
 
89
        /* Convert any DB->open flags. */
 
90
        if (LF_ISSET(DB_RDONLY))
 
91
                F_SET(dbp, DB_AM_RDONLY);
 
92
        if (LF_ISSET(DB_DIRTY_READ))
 
93
                F_SET(dbp, DB_AM_DIRTY);
 
94
 
 
95
        /* Fill in the type. */
 
96
        dbp->type = type;
 
97
 
 
98
        /*
 
99
         * If we're opening a subdatabase, we have to open (and potentially
 
100
         * create) the main database, and then get (and potentially store)
 
101
         * our base page number in that database.  Then, we can finally open
 
102
         * the subdatabase.
 
103
         */
 
104
        if ((ret = __db_dbopen(
 
105
            dbp, txn, name, subdb, flags, mode, PGNO_BASE_MD)) != 0)
 
106
                goto err;
 
107
 
 
108
        /*
 
109
         * You can open the database that describes the subdatabases in the
 
110
         * rest of the file read-only.  The content of each key's data is
 
111
         * unspecified and applications should never be adding new records
 
112
         * or updating existing records.  However, during recovery, we need
 
113
         * to open these databases R/W so we can redo/undo changes in them.
 
114
         * Likewise, we need to open master databases read/write during
 
115
         * rename and remove so we can be sure they're fully sync'ed, so
 
116
         * we provide an override flag for the purpose.
 
117
         */
 
118
        if (subdb == NULL && !IS_RECOVERING(dbenv) && !LF_ISSET(DB_RDONLY) &&
 
119
            !LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) {
 
120
                __db_err(dbenv,
 
121
    "files containing multiple databases may only be opened read-only");
 
122
                ret = EINVAL;
 
123
                goto err;
 
124
        }
 
125
 
 
126
err:    /* If we were successful, don't discard the file on close. */
 
127
        if (ret == 0)
 
128
                /* If we were successful, don't discard the file on close. */
 
129
                F_CLR(dbp, DB_AM_DISCARD | DB_AM_CREATED | DB_AM_CREATED_MSTR);
 
130
        else {
 
131
                /*
 
132
                 * If we are not transactional, we need to remove the
 
133
                 * databases/subdatabases.  If we are transactional, then
 
134
                 * the abort of the child transaction should take care of
 
135
                 * cleaning them up.
 
136
                 */
 
137
                remove_me = txn == NULL && F_ISSET(dbp, DB_AM_CREATED);
 
138
                remove_master = txn == NULL && F_ISSET(dbp, DB_AM_CREATED_MSTR);
 
139
 
 
140
                /*
 
141
                 * If we had an error, it may have happened before or after
 
142
                 * we actually logged the open.  If it happened before, then
 
143
                 * abort won't know anything about it and won't close or
 
144
                 * refresh the dbp, so we need to do it explicitly.
 
145
                 */
 
146
                (void)__db_refresh(dbp, txn, DB_NOSYNC);
 
147
        }
 
148
 
 
149
        /* Remove anyone we created. */
 
150
        if (remove_master || (subdb == NULL && remove_me))
 
151
                /* Remove file. */
 
152
                (void)dbenv->dbremove(dbenv, txn, name, NULL, 0);
 
153
        else if (remove_me)
 
154
                /* Remove subdatabase. */
 
155
                (void)dbenv->dbremove(dbenv, txn, name, subdb, 0);
 
156
 
 
157
        /* Commit for DB_AUTO_COMMIT. */
 
158
        if (txn_local) {
 
159
                if (ret == 0)
 
160
                        ret = txn->commit(txn, 0);
 
161
                else
 
162
                        if ((t_ret = txn->abort(txn)) != 0)
 
163
                                ret = __db_panic(dbenv, t_ret);
 
164
        }
 
165
 
 
166
        return (ret);
 
167
}
 
168
 
 
169
/*
 
170
 * __db_dbopen --
 
171
 *      Open a database.  This routine  gets called in three different ways.
 
172
 * 1. It can be called to open a file/database.  In this case, subdb will
 
173
 *    be NULL and meta_pgno will be PGNO_BASE_MD.
 
174
 * 2. It can be called to open a subdatabase during normal operation.  In
 
175
 *    this case, name and subname will both be non-NULL and meta_pgno will
 
176
 *    be PGNO_BAS_MD (also PGNO_INVALID).
 
177
 * 3. It can be called during recovery to open a subdatabase in which case
 
178
 *    name will be non-NULL, subname mqy be NULL and meta-pgno will be
 
179
 *    a valid pgno (i.e., not PGNO_BASE_MD).
 
180
 *
 
181
 * PUBLIC: int __db_dbopen __P((DB *, DB_TXN *,
 
182
 * PUBLIC:     const char *, const char *, u_int32_t, int, db_pgno_t));
 
183
 */
 
184
int
 
185
__db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
 
186
        DB *dbp;
 
187
        DB_TXN *txn;
 
188
        const char *name, *subdb;
 
189
        u_int32_t flags;
 
190
        int mode;
 
191
        db_pgno_t meta_pgno;
 
192
{
 
193
        DB_ENV *dbenv;
 
194
        int ret;
 
195
        u_int32_t id;
 
196
 
 
197
        dbenv = dbp->dbenv;
 
198
        id = TXN_INVALID;
 
199
        if (txn != NULL)
 
200
                F_SET(dbp, DB_AM_TXN);
 
201
 
 
202
        DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, name);
 
203
        /*
 
204
         * If name is NULL, it's always a create, so make sure that we
 
205
         * have a type specified.  It would be nice if this checking
 
206
         * were done in __db_open where most of the interface checking
 
207
         * is done, but this interface (__db_dbopen) is used by the
 
208
         * recovery and limbo system, so we need to safeguard this
 
209
         * interface as well.
 
210
         */
 
211
        if (name == NULL) {
 
212
                F_SET(dbp, DB_AM_INMEM);
 
213
 
 
214
                if (dbp->type == DB_UNKNOWN) {
 
215
                        __db_err(dbenv,
 
216
                            "DBTYPE of unknown without existing file");
 
217
                        return (EINVAL);
 
218
                }
 
219
 
 
220
                if (dbp->pgsize == 0)
 
221
                        dbp->pgsize = DB_DEF_IOSIZE;
 
222
 
 
223
                /*
 
224
                 * If the file is a temporary file and we're doing locking,
 
225
                 * then we have to create a unique file ID.  We can't use our
 
226
                 * normal dev/inode pair (or whatever this OS uses in place of
 
227
                 * dev/inode pairs) because no backing file will be created
 
228
                 * until the mpool cache is filled forcing the buffers to disk.
 
229
                 * Grab a random locker ID to use as a file ID.  The created
 
230
                 * ID must never match a potential real file ID -- we know it
 
231
                 * won't because real file IDs contain a time stamp after the
 
232
                 * dev/inode pair, and we're simply storing a 4-byte value.
 
233
                 *
 
234
                 * !!!
 
235
                 * Store the locker in the file id structure -- we can get it
 
236
                 * from there as necessary, and it saves having two copies.
 
237
                 */
 
238
                if (LOCKING_ON(dbenv) && (ret = dbenv->lock_id(dbenv,
 
239
                    (u_int32_t *)dbp->fileid)) != 0)
 
240
                        return (ret);
 
241
        } else if (subdb == NULL && meta_pgno == PGNO_BASE_MD) {
 
242
                /* Open/create the underlying file.  Acquire locks. */
 
243
                if ((ret =
 
244
                    __fop_file_setup(dbp, txn, name, mode, flags, &id)) != 0)
 
245
                        return (ret);
 
246
        } else {
 
247
                if ((ret = __fop_subdb_setup(dbp,
 
248
                    txn, name, subdb, mode, flags)) != 0)
 
249
                        return (ret);
 
250
                meta_pgno = dbp->meta_pgno;
 
251
        }
 
252
 
 
253
        /*
 
254
         * If we created the file, set the truncate flag for the mpool.  This
 
255
         * isn't for anything we've done, it's protection against stupid user
 
256
         * tricks: if the user deleted a file behind Berkeley DB's back, we
 
257
         * may still have pages in the mpool that match the file's "unique" ID.
 
258
         *
 
259
         * Note that if we're opening a subdatabase, we don't want to set
 
260
         * the TRUNCATE flag even if we just created the file--we already
 
261
         * opened and updated the master using access method interfaces,
 
262
         * so we don't want to get rid of any pages that are in the mpool.
 
263
         * If we created the file when we opened the master, we already hit
 
264
         * this check in a non-subdb context then.
 
265
         */
 
266
        if (subdb == NULL && F_ISSET(dbp, DB_AM_CREATED))
 
267
                LF_SET(DB_TRUNCATE);
 
268
 
 
269
        /* Set up the underlying environment. */
 
270
        if ((ret = __db_dbenv_setup(dbp, txn, name, id, flags)) != 0)
 
271
                return (ret);
 
272
 
 
273
        /*
 
274
         * Set the open flag.  We use it to mean that the dbp has gone
 
275
         * through mpf setup, including dbreg_register.  Also, below,
 
276
         * the underlying access method open functions may want to do
 
277
         * things like acquire cursors, so the open flag has to be set
 
278
         * before calling them.
 
279
         */
 
280
        F_SET(dbp, DB_AM_OPEN_CALLED);
 
281
 
 
282
        /*
 
283
         * For unnamed files, we need to actually create the file now
 
284
         * that the mpool is open.
 
285
         */
 
286
        if (name == NULL && (ret = __db_new_file(dbp, txn, NULL, NULL)) != 0)
 
287
                return (ret);
 
288
 
 
289
        switch (dbp->type) {
 
290
        case DB_BTREE:
 
291
                ret = __bam_open(dbp, txn, name, meta_pgno, flags);
 
292
                break;
 
293
        case DB_HASH:
 
294
                ret = __ham_open(dbp, txn, name, meta_pgno, flags);
 
295
                break;
 
296
        case DB_RECNO:
 
297
                ret = __ram_open(dbp, txn, name, meta_pgno, flags);
 
298
                break;
 
299
        case DB_QUEUE:
 
300
                ret = __qam_open(dbp, txn, name, meta_pgno, mode, flags);
 
301
                break;
 
302
        case DB_UNKNOWN:
 
303
                return (__db_unknown_type(dbenv, "__db_dbopen", dbp->type));
 
304
        }
 
305
        if (ret != 0)
 
306
                goto err;
 
307
 
 
308
        DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, name);
 
309
 
 
310
        /*
 
311
         * Unnamed files don't need handle locks, so we only have to check
 
312
         * for a handle lock downgrade or lockevent in the case of named
 
313
         * files.
 
314
         */
 
315
        if (!F_ISSET(dbp, DB_AM_RECOVER) &&
 
316
            name != NULL && LOCK_ISSET(dbp->handle_lock)) {
 
317
                if (txn != NULL) {
 
318
                        ret = __txn_lockevent(dbenv,
 
319
                            txn, dbp, &dbp->handle_lock, dbp->lid);
 
320
                } else if (LOCKING_ON(dbenv))
 
321
                        /* Trade write handle lock for read handle lock. */
 
322
                        ret = __lock_downgrade(dbenv,
 
323
                            &dbp->handle_lock, DB_LOCK_READ, 0);
 
324
        }
 
325
DB_TEST_RECOVERY_LABEL
 
326
err:
 
327
        return (ret);
 
328
}
 
329
 
 
330
/*
 
331
 * __db_new_file --
 
332
 *      Create a new database file.
 
333
 *
 
334
 * PUBLIC: int __db_new_file __P((DB *, DB_TXN *, DB_FH *, const char *));
 
335
 */
 
336
int
 
337
__db_new_file(dbp, txn, fhp, name)
 
338
        DB *dbp;
 
339
        DB_TXN *txn;
 
340
        DB_FH *fhp;
 
341
        const char *name;
 
342
{
 
343
        int ret;
 
344
 
 
345
        switch (dbp->type) {
 
346
        case DB_BTREE:
 
347
        case DB_RECNO:
 
348
                ret = __bam_new_file(dbp, txn, fhp, name);
 
349
                break;
 
350
        case DB_HASH:
 
351
                ret = __ham_new_file(dbp, txn, fhp, name);
 
352
                break;
 
353
        case DB_QUEUE:
 
354
                ret = __qam_new_file(dbp, txn, fhp, name);
 
355
                break;
 
356
        default:
 
357
                __db_err(dbp->dbenv,
 
358
                    "%s: Invalid type %d specified", name, dbp->type);
 
359
                ret = EINVAL;
 
360
                break;
 
361
        }
 
362
 
 
363
        DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, name);
 
364
        /* Sync the file in preparation for moving it into place. */
 
365
        if (ret == 0 && fhp != NULL)
 
366
                ret = __os_fsync(dbp->dbenv, fhp);
 
367
 
 
368
        DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name);
 
369
 
 
370
DB_TEST_RECOVERY_LABEL
 
371
        return (ret);
 
372
}
 
373
 
 
374
/*
 
375
 * __db_init_subdb --
 
376
 *      Initialize the dbp for a subdb.
 
377
 *
 
378
 * PUBLIC: int __db_init_subdb __P((DB *, DB *, const char *, DB_TXN *));
 
379
 */
 
380
int
 
381
__db_init_subdb(mdbp, dbp, name, txn)
 
382
        DB *mdbp, *dbp;
 
383
        const char *name;
 
384
        DB_TXN *txn;
 
385
{
 
386
        DBMETA *meta;
 
387
        DB_MPOOLFILE *mpf;
 
388
        int ret, t_ret;
 
389
 
 
390
        ret = 0;
 
391
        if (!F_ISSET(dbp, DB_AM_CREATED)) {
 
392
                /* Subdb exists; read meta-data page and initialize. */
 
393
                mpf = mdbp->mpf;
 
394
                if  ((ret = mpf->get(mpf, &dbp->meta_pgno, 0, &meta)) != 0)
 
395
                        goto err;
 
396
                ret = __db_meta_setup(mdbp->dbenv, dbp, name, meta, 0, 0);
 
397
                if ((t_ret = mpf->put(mpf, meta, 0)) != 0 && ret == 0)
 
398
                        ret = t_ret;
 
399
                /*
 
400
                 * If __db_meta_setup found that the meta-page hadn't
 
401
                 * been written out during recovery, we can just return.
 
402
                 */
 
403
                if (ret == ENOENT)
 
404
                        ret = 0;
 
405
                goto err;
 
406
        }
 
407
 
 
408
        /* Handle the create case here. */
 
409
        switch (dbp->type) {
 
410
        case DB_BTREE:
 
411
        case DB_RECNO:
 
412
                ret = __bam_new_subdb(mdbp, dbp, txn);
 
413
                break;
 
414
        case DB_HASH:
 
415
                ret = __ham_new_subdb(mdbp, dbp, txn);
 
416
                break;
 
417
        case DB_QUEUE:
 
418
                ret = EINVAL;
 
419
                break;
 
420
        default:
 
421
                __db_err(dbp->dbenv,
 
422
                    "Invalid subdatabase type %d specified", dbp->type);
 
423
                return (EINVAL);
 
424
        }
 
425
 
 
426
err:    return (ret);
 
427
}
 
428
 
 
429
/*
 
430
 * __db_chk_meta --
 
431
 *      Take a buffer containing a meta-data page and check it for a checksum
 
432
 *      (and verify the checksum if necessary) and possibly decrypt it.
 
433
 *
 
434
 *      Return 0 on success, >0 (errno) on error, -1 on checksum mismatch.
 
435
 *
 
436
 * PUBLIC: int __db_chk_meta __P((DB_ENV *, DB *, DBMETA *, int));
 
437
 */
 
438
int
 
439
__db_chk_meta(dbenv, dbp, meta, do_metachk)
 
440
        DB_ENV *dbenv;
 
441
        DB *dbp;
 
442
        DBMETA *meta;
 
443
        int do_metachk;
 
444
{
 
445
        int is_hmac, ret;
 
446
        u_int8_t *chksum;
 
447
 
 
448
        ret = 0;
 
449
 
 
450
        if (FLD_ISSET(meta->metaflags, DBMETA_CHKSUM)) {
 
451
                if (dbp != NULL)
 
452
                        F_SET(dbp, DB_AM_CHKSUM);
 
453
 
 
454
                is_hmac = meta->encrypt_alg == 0 ? 0 : 1;
 
455
                chksum = ((BTMETA *)meta)->chksum;
 
456
                if (do_metachk && ((ret = __db_check_chksum(dbenv,
 
457
                    (DB_CIPHER *)dbenv->crypto_handle, chksum, meta,
 
458
                    DBMETASIZE, is_hmac)) != 0))
 
459
                        return (ret);
 
460
        }
 
461
 
 
462
#ifdef HAVE_CRYPTO
 
463
        ret = __crypto_decrypt_meta(dbenv, dbp, (u_int8_t *)meta, do_metachk);
 
464
#endif
 
465
        return (ret);
 
466
}
 
467
 
 
468
/*
 
469
 * __db_meta_setup --
 
470
 *
 
471
 * Take a buffer containing a meta-data page and figure out if it's
 
472
 * valid, and if so, initialize the dbp from the meta-data page.
 
473
 *
 
474
 * PUBLIC: int __db_meta_setup __P((DB_ENV *,
 
475
 * PUBLIC:     DB *, const char *, DBMETA *, u_int32_t, int));
 
476
 */
 
477
int
 
478
__db_meta_setup(dbenv, dbp, name, meta, oflags, do_metachk)
 
479
        DB_ENV *dbenv;
 
480
        DB *dbp;
 
481
        const char *name;
 
482
        DBMETA *meta;
 
483
        u_int32_t oflags;
 
484
        int do_metachk;
 
485
{
 
486
        u_int32_t flags, magic;
 
487
        int ret;
 
488
 
 
489
        ret = 0;
 
490
 
 
491
        /*
 
492
         * Figure out what access method we're dealing with, and then
 
493
         * call access method specific code to check error conditions
 
494
         * based on conflicts between the found file and application
 
495
         * arguments.  A found file overrides some user information --
 
496
         * we don't consider it an error, for example, if the user set
 
497
         * an expected byte order and the found file doesn't match it.
 
498
         */
 
499
        F_CLR(dbp, DB_AM_SWAP);
 
500
        magic = meta->magic;
 
501
 
 
502
swap_retry:
 
503
        switch (magic) {
 
504
        case DB_BTREEMAGIC:
 
505
        case DB_HASHMAGIC:
 
506
        case DB_QAMMAGIC:
 
507
        case DB_RENAMEMAGIC:
 
508
                break;
 
509
        case 0:
 
510
                /*
 
511
                 * The only time this should be 0 is if we're in the
 
512
                 * midst of opening a subdb during recovery and that
 
513
                 * subdatabase had its meta-data page allocated, but
 
514
                 * not yet initialized.
 
515
                 */
 
516
                if (F_ISSET(dbp, DB_AM_SUBDB) && ((IS_RECOVERING(dbenv) &&
 
517
                    F_ISSET((DB_LOG *) dbenv->lg_handle, DBLOG_FORCE_OPEN)) ||
 
518
                    meta->pgno != PGNO_INVALID))
 
519
                        return (ENOENT);
 
520
 
 
521
                goto bad_format;
 
522
        default:
 
523
                if (F_ISSET(dbp, DB_AM_SWAP))
 
524
                        goto bad_format;
 
525
 
 
526
                M_32_SWAP(magic);
 
527
                F_SET(dbp, DB_AM_SWAP);
 
528
                goto swap_retry;
 
529
        }
 
530
 
 
531
        /*
 
532
         * We can only check the meta page if we are sure we have a meta page.
 
533
         * If it is random data, then this check can fail.  So only now can we
 
534
         * checksum and decrypt.  Don't distinguish between configuration and
 
535
         * checksum match errors here, because we haven't opened the database
 
536
         * and even a checksum error isn't a reason to panic the environment.
 
537
         */
 
538
        if ((ret = __db_chk_meta(dbenv, dbp, meta, do_metachk)) != 0) {
 
539
                if (ret == -1)
 
540
                        __db_err(dbenv,
 
541
                            "%s: metadata page checksum error", name);
 
542
                goto bad_format;
 
543
        }
 
544
 
 
545
        switch (magic) {
 
546
        case DB_BTREEMAGIC:
 
547
                flags = meta->flags;
 
548
                if (F_ISSET(dbp, DB_AM_SWAP))
 
549
                        M_32_SWAP(flags);
 
550
                if (LF_ISSET(BTM_RECNO))
 
551
                        dbp->type = DB_RECNO;
 
552
                else
 
553
                        dbp->type = DB_BTREE;
 
554
                if ((oflags & DB_TRUNCATE) == 0 && (ret =
 
555
                    __bam_metachk(dbp, name, (BTMETA *)meta)) != 0)
 
556
                        return (ret);
 
557
                break;
 
558
        case DB_HASHMAGIC:
 
559
                dbp->type = DB_HASH;
 
560
                if ((oflags & DB_TRUNCATE) == 0 && (ret =
 
561
                    __ham_metachk(dbp, name, (HMETA *)meta)) != 0)
 
562
                        return (ret);
 
563
                break;
 
564
        case DB_QAMMAGIC:
 
565
                dbp->type = DB_QUEUE;
 
566
                if ((oflags & DB_TRUNCATE) == 0 && (ret =
 
567
                    __qam_metachk(dbp, name, (QMETA *)meta)) != 0)
 
568
                        return (ret);
 
569
                break;
 
570
        case DB_RENAMEMAGIC:
 
571
                F_SET(dbp, DB_AM_IN_RENAME);
 
572
                break;
 
573
        }
 
574
        return (0);
 
575
 
 
576
bad_format:
 
577
        __db_err(dbenv, "%s: unexpected file type or format", name);
 
578
        return (ret == 0 ? EINVAL : ret);
 
579
}
 
580
 
 
581
/*
 
582
 * __db_openchk --
 
583
 *      Interface error checking for open calls.
 
584
 */
 
585
static int
 
586
__db_openchk(dbp, txn, name, subdb, type, flags)
 
587
        DB *dbp;
 
588
        DB_TXN *txn;
 
589
        const char *name, *subdb;
 
590
        DBTYPE type;
 
591
        u_int32_t flags;
 
592
{
 
593
        DB_ENV *dbenv;
 
594
        int ret;
 
595
        u_int32_t ok_flags;
 
596
 
 
597
        dbenv = dbp->dbenv;
 
598
 
 
599
        /* Validate arguments. */
 
600
#define OKFLAGS                                                         \
 
601
    (DB_AUTO_COMMIT | DB_CREATE | DB_DIRTY_READ | DB_EXCL |             \
 
602
     DB_FCNTL_LOCKING | DB_NOMMAP | DB_RDONLY | DB_RDWRMASTER |         \
 
603
     DB_THREAD | DB_TRUNCATE | DB_WRITEOPEN)
 
604
        if ((ret = __db_fchk(dbenv, "DB->open", flags, OKFLAGS)) != 0)
 
605
                return (ret);
 
606
        if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE))
 
607
                return (__db_ferr(dbenv, "DB->open", 1));
 
608
        if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE))
 
609
                return (__db_ferr(dbenv, "DB->open", 1));
 
610
 
 
611
#ifdef  HAVE_VXWORKS
 
612
        if (LF_ISSET(DB_TRUNCATE)) {
 
613
                __db_err(dbenv, "DB_TRUNCATE unsupported in VxWorks");
 
614
                return (__db_eopnotsup(dbenv));
 
615
        }
 
616
#endif
 
617
        switch (type) {
 
618
        case DB_UNKNOWN:
 
619
                if (LF_ISSET(DB_CREATE|DB_TRUNCATE)) {
 
620
                        __db_err(dbenv,
 
621
            "%s: DB_UNKNOWN type specified with DB_CREATE or DB_TRUNCATE",
 
622
                            name);
 
623
                        return (EINVAL);
 
624
                }
 
625
                ok_flags = 0;
 
626
                break;
 
627
        case DB_BTREE:
 
628
                ok_flags = DB_OK_BTREE;
 
629
                break;
 
630
        case DB_HASH:
 
631
                ok_flags = DB_OK_HASH;
 
632
                break;
 
633
        case DB_QUEUE:
 
634
                ok_flags = DB_OK_QUEUE;
 
635
                break;
 
636
        case DB_RECNO:
 
637
                ok_flags = DB_OK_RECNO;
 
638
                break;
 
639
        default:
 
640
                __db_err(dbenv, "unknown type: %lu", (u_long)type);
 
641
                return (EINVAL);
 
642
        }
 
643
        if (ok_flags)
 
644
                DB_ILLEGAL_METHOD(dbp, ok_flags);
 
645
 
 
646
        /* The environment may have been created, but never opened. */
 
647
        if (!F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_OPEN_CALLED)) {
 
648
                __db_err(dbenv, "environment not yet opened");
 
649
                return (EINVAL);
 
650
        }
 
651
 
 
652
        /*
 
653
         * Historically, you could pass in an environment that didn't have a
 
654
         * mpool, and DB would create a private one behind the scenes.  This
 
655
         * no longer works.
 
656
         */
 
657
        if (!F_ISSET(dbenv, DB_ENV_DBLOCAL) && !MPOOL_ON(dbenv)) {
 
658
                __db_err(dbenv, "environment did not include a memory pool");
 
659
                return (EINVAL);
 
660
        }
 
661
 
 
662
        /*
 
663
         * You can't specify threads during DB->open if subsystems in the
 
664
         * environment weren't configured with them.
 
665
         */
 
666
        if (LF_ISSET(DB_THREAD) &&
 
667
            !F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_THREAD)) {
 
668
                __db_err(dbenv, "environment not created using DB_THREAD");
 
669
                return (EINVAL);
 
670
        }
 
671
 
 
672
        /* DB_TRUNCATE is not transaction recoverable. */
 
673
        if (LF_ISSET(DB_TRUNCATE) && txn != NULL) {
 
674
                __db_err(dbenv,
 
675
                    "DB_TRUNCATE illegal with transaction specified");
 
676
                return (EINVAL);
 
677
        }
 
678
 
 
679
        /* Subdatabase checks. */
 
680
        if (subdb != NULL) {
 
681
                /* Subdatabases must be created in named files. */
 
682
                if (name == NULL) {
 
683
                        __db_err(dbenv,
 
684
                    "multiple databases cannot be created in temporary files");
 
685
                        return (EINVAL);
 
686
                }
 
687
 
 
688
                /* Truncate is a physical file operation */
 
689
                if (LF_ISSET(DB_TRUNCATE)) {
 
690
                        __db_err(dbenv,
 
691
                            "DB_TRUNCATE illegal with multiple databases");
 
692
                        return (EINVAL);
 
693
                }
 
694
 
 
695
                /* QAM can't be done as a subdatabase. */
 
696
                if (type == DB_QUEUE) {
 
697
                        __db_err(dbenv, "Queue databases must be one-per-file");
 
698
                        return (EINVAL);
 
699
                }
 
700
        }
 
701
 
 
702
        return (0);
 
703
}