~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to rpmdb/db1.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** \ingroup db1
 
2
 * \file rpmdb/db1.c
 
3
 */
 
4
 
 
5
#include "system.h"
 
6
 
 
7
/*@unused@*/ static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
 
8
 
 
9
#define _mymemset(_a, _b, _c)
 
10
 
 
11
#include <rpmio_internal.h>
 
12
#include <rpmlib.h>
 
13
#include <rpmmacro.h>   /* XXX rpmGenPath */
 
14
#include <rpmurl.h>     /* XXX urlGetPath */
 
15
 
 
16
#include "falloc.h"
 
17
#include "misc.h"
 
18
 
 
19
#include "rpmdb.h"
 
20
 
 
21
/* XXX must follow rpmdb.h */
 
22
#define DB_VERSION_MAJOR        1
 
23
#define DB_VERSION_MINOR        85
 
24
#define DB_VERSION_PATCH        0
 
25
 
 
26
struct _DBT1 {
 
27
    void * data;        /* data */
 
28
    size_t size;        /* data length */
 
29
};
 
30
 
 
31
#undef  DBT
 
32
#define DBT struct _DBT1
 
33
 
 
34
#include "debug.h"
 
35
 
 
36
/*@access Header@*/             /* XXX compared with NULL */
 
37
/*@access rpmdb@*/
 
38
/*@access dbiIndex@*/
 
39
/*@access dbiIndexSet@*/
 
40
/*@-onlytrans@*/
 
41
 
 
42
#ifdef  DYING
 
43
/* XXX remap DB3 types back into DB1 types */
 
44
static inline DBTYPE db3_to_dbtype(int dbitype)
 
45
{
 
46
    switch(dbitype) {
 
47
    case 1:     return DB_BTREE;
 
48
    case 2:     return DB_HASH;
 
49
    case 3:     return DB_RECNO;
 
50
    case 4:     return DB_HASH;         /* XXX W2DO? */
 
51
    case 5:     return DB_HASH;         /* XXX W2DO? */
 
52
    }
 
53
    /*@notreached@*/ return DB_HASH;
 
54
}
 
55
 
 
56
/*@-shadow@*/
 
57
static /*@observer@*/ char * db_strerror(int error)
 
58
/*@=shadow@*/
 
59
{
 
60
    if (error == 0)
 
61
        return ("Successful return: 0");
 
62
    if (error > 0)
 
63
        return (strerror(error));
 
64
 
 
65
    switch (error) {
 
66
    default:
 
67
      {
 
68
        /*
 
69
         * !!!
 
70
         * Room for a 64-bit number + slop.  This buffer is only used
 
71
         * if we're given an unknown error, which should never happen.
 
72
         * Note, however, we're no longer thread-safe if it does.
 
73
         */
 
74
        static char ebuf[40];
 
75
        char * t = ebuf;
 
76
 
 
77
        *t = '\0';
 
78
        t = stpcpy(t, "Unknown error: ");
 
79
        sprintf(t, "%d", error);
 
80
        return(ebuf);
 
81
      }
 
82
    }
 
83
    /*@notreached@*/
 
84
}
 
85
 
 
86
static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
 
87
        /*@modifies dbi, fileSystem @*/
 
88
{
 
89
    int rc = 0;
 
90
 
 
91
    if (error == 0)
 
92
        rc = 0;
 
93
    else if (error < 0)
 
94
        rc = errno;
 
95
    else if (error > 0)
 
96
        rc = -1;
 
97
 
 
98
    if (printit && rc) {
 
99
        if (msg)
 
100
            rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
 
101
                dbi->dbi_api, rc, msg, db_strerror(error));
 
102
        else
 
103
            rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
 
104
                dbi->dbi_api, rc, db_strerror(error));
 
105
    }
 
106
 
 
107
    return rc;
 
108
}
 
109
#endif  /* DYING */
 
110
 
 
111
static int db1sync(dbiIndex dbi, /*@unused@*/ unsigned int flags)
 
112
        /*@modifies fileSystem @*/
 
113
{
 
114
    int rc = 0;
 
115
 
 
116
    if (dbi->dbi_db) {
 
117
        if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
 
118
            FD_t pkgs = dbi->dbi_db;
 
119
            int fdno = Fileno(pkgs);
 
120
            if (fdno >= 0 && (rc = fsync(fdno)) != 0)
 
121
                rc = errno;
 
122
        }
 
123
#ifdef  DYING
 
124
        else {
 
125
            DB * db = dbi->dbi_db;
 
126
            rc = db->sync(db, flags);
 
127
            rc = cvtdberr(dbi, "db->sync", rc, _debug);
 
128
        }
 
129
#endif
 
130
    }
 
131
 
 
132
    return rc;
 
133
}
 
134
 
 
135
/*@null@*/ static void * doGetRecord(dbiIndex dbi, unsigned int offset)
 
136
        /*@modifies dbi, fileSystem @*/
 
137
{
 
138
    FD_t pkgs = dbi->dbi_db;
 
139
    void * uh = NULL;
 
140
    Header h = NULL;
 
141
    const char ** fileNames;
 
142
    int fileCount = 0;
 
143
    int lasto = 0;
 
144
    int i;
 
145
 
 
146
retry:
 
147
    if (offset >= fadGetFileSize(pkgs))
 
148
        goto exit;
 
149
 
 
150
    (void)Fseek(pkgs, offset, SEEK_SET);
 
151
 
 
152
    h = headerRead(pkgs, HEADER_MAGIC_NO);
 
153
 
 
154
    /* let's sanity check this record a bit, otherwise just skip it */
 
155
    if (h != NULL &&
 
156
        !(      headerIsEntry(h, RPMTAG_NAME) &&
 
157
                headerIsEntry(h, RPMTAG_VERSION) &&
 
158
                headerIsEntry(h, RPMTAG_RELEASE) &&
 
159
                headerIsEntry(h, RPMTAG_BUILDTIME)))
 
160
    {
 
161
        h = headerFree(h);
 
162
    }
 
163
 
 
164
    if (h == NULL) {
 
165
        /* XXX HACK: try to reconnect broken chain. */
 
166
        if (lasto == 0) {
 
167
            rpmMessage(RPMMESS_WARNING,
 
168
  _("Broken package chain at offset %d(0x%08x), attempting to reconnect ...\n"),
 
169
                        (int) offset, offset);
 
170
            lasto = (offset ? offset : -1);
 
171
            offset = fadNextOffset(pkgs, offset);
 
172
            if (offset > 0)
 
173
                goto retry;
 
174
        }
 
175
        goto exit;
 
176
    }
 
177
 
 
178
    if (lasto) {
 
179
        rpmMessage(RPMMESS_WARNING,
 
180
                _("Reconnecting broken chain at offset %d(0x%08x).\n"),
 
181
                (int) offset, offset);
 
182
        dbi->dbi_lastoffset = offset;
 
183
    }
 
184
 
 
185
    /* Retrofit "Provide: name = EVR" for binary packages. */
 
186
    providePackageNVR(h);
 
187
 
 
188
    /*
 
189
     * The RPM used to build much of RH 5.1 could produce packages whose
 
190
     * file lists did not have leading /'s. Now is a good time to fix that.
 
191
     */
 
192
 
 
193
    /*
 
194
     * If this tag isn't present, either no files are in the package or
 
195
     * we're dealing with a package that has just the compressed file name
 
196
     * list.
 
197
     */
 
198
    if (!headerGetEntryMinMemory(h, RPMTAG_OLDFILENAMES, NULL, 
 
199
                           (const void **) &fileNames, &fileCount))
 
200
        goto exit;
 
201
 
 
202
    for (i = 0; i < fileCount; i++) 
 
203
        if (*fileNames[i] != '/') break;
 
204
 
 
205
    if (i == fileCount) {
 
206
        free(fileNames);
 
207
    } else {    /* bad header -- let's clean it up */
 
208
        const char ** newFileNames = alloca(sizeof(*newFileNames) * fileCount);
 
209
        for (i = 0; i < fileCount; i++) {
 
210
            char * newFileName = alloca(strlen(fileNames[i]) + 2);
 
211
            if (*fileNames[i] != '/') {
 
212
                newFileName[0] = '/';
 
213
                newFileName[1] = '\0';
 
214
            } else
 
215
                newFileName[0] = '\0';
 
216
            strcat(newFileName, fileNames[i]);
 
217
            newFileNames[i] = newFileName;
 
218
        }
 
219
 
 
220
        free(fileNames);
 
221
 
 
222
        (void) headerModifyEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE, 
 
223
                          newFileNames, fileCount);
 
224
    }
 
225
 
 
226
    /*
 
227
     * The file list was moved to a more compressed format which not
 
228
     * only saves memory (nice), but gives fingerprinting a nice, fat
 
229
     * speed boost (very nice). Go ahead and convert old headers to
 
230
     * the new style (this is a noop for new headers).
 
231
     */
 
232
    compressFilelist(h);
 
233
 
 
234
exit:
 
235
    if (h != NULL) {
 
236
        uh = headerUnload(h);
 
237
        h = headerFree(h);
 
238
    }
 
239
    return uh;
 
240
}
 
241
 
 
242
static int db1copen(/*@unused@*/ dbiIndex dbi,
 
243
                /*@unused@*/ DBC ** dbcp, unsigned int flags)
 
244
        /*@modifies *dbcp @*/
 
245
{
 
246
    /* XXX per-iterator cursors need to be set to non-NULL. */
 
247
    if (flags)
 
248
        *dbcp = (DBC *)-1;
 
249
    return 0;
 
250
}
 
251
 
 
252
static int db1cclose(dbiIndex dbi,
 
253
                /*@unused@*/ DBC * dbcursor, /*@unused@*/ unsigned int flags)
 
254
        /*@modifies dbi @*/
 
255
{
 
256
    dbi->dbi_lastoffset = 0;
 
257
    return 0;
 
258
}
 
259
 
 
260
/*@-compmempass@*/
 
261
static int db1cget(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
 
262
                /*@null@*/ void ** keyp,
 
263
                /*@null@*/ size_t * keylen, 
 
264
                /*@null@*/ void ** datap, 
 
265
                /*@null@*/ size_t * datalen,
 
266
                /*@unused@*/ unsigned int flags)
 
267
        /*@modifies dbi, *keyp, *keylen, *datap, *datalen, fileSystem @*/
 
268
{
 
269
    DBT key, data;
 
270
    int rc = 0;
 
271
 
 
272
    if (dbi == NULL)
 
273
        return EFAULT;
 
274
 
 
275
    memset(&key, 0, sizeof(key));
 
276
    memset(&data, 0, sizeof(data));
 
277
    /*@-unqualifiedtrans@*/
 
278
    if (keyp)           key.data = *keyp;
 
279
    if (keylen)         key.size = *keylen;
 
280
    if (datap)          data.data = *datap;
 
281
    if (datalen)        data.size = *datalen;
 
282
    /*@=unqualifiedtrans@*/
 
283
 
 
284
    if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
 
285
        FD_t pkgs = dbi->dbi_db;
 
286
        unsigned int offset;
 
287
        unsigned int newSize;
 
288
 
 
289
        if (key.data == NULL) { /* XXX simulated DB_NEXT */
 
290
            if (dbi->dbi_lastoffset == 0) {
 
291
                dbi->dbi_lastoffset = fadFirstOffset(pkgs);
 
292
            } else {
 
293
                dbi->dbi_lastoffset = fadNextOffset(pkgs, dbi->dbi_lastoffset);
 
294
            }
 
295
            /*@-immediatetrans@*/
 
296
            key.data = &dbi->dbi_lastoffset;
 
297
            /*@=immediatetrans@*/
 
298
            key.size = sizeof(dbi->dbi_lastoffset);
 
299
 
 
300
            /* Catch end-of-chain conditions. */
 
301
            if (dbi->dbi_lastoffset == 0)
 
302
                goto bail;
 
303
        }
 
304
 
 
305
        memcpy(&offset, key.data, sizeof(offset));
 
306
        /* XXX hack to pass sizeof header to fadAlloc */
 
307
        newSize = data.size;
 
308
 
 
309
        if (offset == 0) {      /* XXX simulated offset 0 record */
 
310
            offset = fadAlloc(pkgs, newSize);
 
311
            if (offset == 0)
 
312
                return ENOMEM;
 
313
            offset--;   /* XXX hack: caller will increment */
 
314
            /* XXX hack: return offset as data, free in db1cput */
 
315
            data.data = xmalloc(sizeof(offset));
 
316
            memcpy(data.data, &offset, sizeof(offset));
 
317
            data.size = sizeof(offset);
 
318
        } else {                /* XXX simulated retrieval */
 
319
            data.data = doGetRecord(dbi, offset);
 
320
            data.size = 0;      /* XXX WRONG */
 
321
        }
 
322
    }
 
323
#ifdef  DYING
 
324
    else {
 
325
        DB * db;
 
326
        int _printit;
 
327
 
 
328
        if ((db = dbi->dbi_db) == NULL)
 
329
            return EFAULT;
 
330
 
 
331
        if (key.data == NULL) {
 
332
            rc = db->seq(db, &key, &data, (dbi->dbi_lastoffset++ ? R_NEXT : R_FIRST));
 
333
            _printit = (rc == 1 ? 0 : _debug);
 
334
            rc = cvtdberr(dbi, "db->seq", rc, _printit);
 
335
        } else {
 
336
            rc = db->get(db, &key, &data, 0);
 
337
            _printit = (rc == 1 ? 0 : _debug);
 
338
            rc = cvtdberr(dbi, "db1cget", rc, _printit);
 
339
        }
 
340
    }
 
341
#else
 
342
    else
 
343
        rc = EINVAL;
 
344
#endif
 
345
 
 
346
bail:
 
347
    if (rc == 0) {
 
348
        if (keyp)       *keyp = key.data;
 
349
        if (keylen)     *keylen = key.size;
 
350
        if (datap)      *datap = data.data;
 
351
        if (datalen)    *datalen = data.size;
 
352
    }
 
353
 
 
354
    /*@-nullstate@*/
 
355
    return rc;
 
356
    /*@=nullstate@*/
 
357
}
 
358
/*@=compmempass@*/
 
359
 
 
360
static int db1cdel(dbiIndex dbi, /*@unused@*/ DBC * dbcursor, const void * keyp,
 
361
                size_t keylen, /*@unused@*/ unsigned int flags)
 
362
        /*@modifies dbi, fileSystem @*/
 
363
{
 
364
    DBT key;
 
365
    int rc = 0;
 
366
 
 
367
    memset(&key, 0, sizeof(key));
 
368
    key.data = (void *)keyp;
 
369
    key.size = keylen;
 
370
 
 
371
    if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
 
372
        FD_t pkgs = dbi->dbi_db;
 
373
        unsigned int offset;
 
374
        memcpy(&offset, keyp, sizeof(offset));
 
375
        fadFree(pkgs, offset);
 
376
    }
 
377
#ifdef  DYING
 
378
    else {
 
379
        DB * db = dbi->dbi_db;
 
380
 
 
381
        if (db)
 
382
            rc = db->del(db, &key, 0);
 
383
        rc = cvtdberr(dbi, "db->del", rc, _debug);
 
384
    }
 
385
#else
 
386
    else
 
387
        rc = EINVAL;
 
388
#endif
 
389
 
 
390
    return rc;
 
391
}
 
392
 
 
393
static int db1cput(dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
 
394
                const void * keyp, size_t keylen,
 
395
                const void * datap, size_t datalen,
 
396
                /*@unused@*/ unsigned int flags)
 
397
        /*@modifies dbi, datap, fileSystem @*/
 
398
{
 
399
    DBT key, data;
 
400
    int rc = 0;
 
401
 
 
402
    memset(&key, 0, sizeof(key));
 
403
    memset(&data, 0, sizeof(data));
 
404
    key.data = (void *)keyp;
 
405
    key.size = keylen;
 
406
    data.data = (void *)datap;
 
407
    data.size = datalen;
 
408
 
 
409
    if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
 
410
        FD_t pkgs = dbi->dbi_db;
 
411
        unsigned int offset;
 
412
 
 
413
        memcpy(&offset, key.data, sizeof(offset));
 
414
 
 
415
        if (offset == 0) {      /* XXX simulated offset 0 record */
 
416
            /* XXX hack: return offset as data, free in db1cput */
 
417
            if (data.size == sizeof(offset))
 
418
                /*@-unqualifiedtrans@*/ free(data.data); /*@=unqualifiedtrans@*/
 
419
        } else {                /* XXX simulated DB_KEYLAST */
 
420
            Header h = headerLoad(data.data);
 
421
            int newSize = headerSizeof(h, HEADER_MAGIC_NO);
 
422
 
 
423
            (void)Fseek(pkgs, offset, SEEK_SET);
 
424
            fdSetContentLength(pkgs, newSize);
 
425
            rc = headerWrite(pkgs, h, HEADER_MAGIC_NO);
 
426
            fdSetContentLength(pkgs, -1);
 
427
            if (rc)
 
428
                rc = EIO;
 
429
            h = headerFree(h);
 
430
        }
 
431
    }
 
432
#ifdef  DYING
 
433
    else {
 
434
        DB * db = dbi->dbi_db;
 
435
 
 
436
        if (db)
 
437
            rc = db->put(db, &key, &data, 0);
 
438
        rc = cvtdberr(dbi, "db->put", rc, _debug);
 
439
    }
 
440
#else
 
441
    else
 
442
        rc = EINVAL;
 
443
#endif
 
444
 
 
445
    return rc;
 
446
}
 
447
 
 
448
static int db1ccount(/*@unused@*/ dbiIndex dbi, /*@unused@*/ DBC * dbcursor,
 
449
                /*@unused@*/ /*@out@*/ unsigned int * countp,
 
450
                /*@unused@*/ unsigned int flags)
 
451
        /*@*/
 
452
{
 
453
    return EINVAL;
 
454
}
 
455
 
 
456
static int db1byteswapped(/*@unused@*/dbiIndex dbi)
 
457
        /*@*/
 
458
{
 
459
    return 0;
 
460
}
 
461
 
 
462
static int db1stat(/*@unused@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
 
463
        /*@*/
 
464
{
 
465
    return EINVAL;
 
466
}
 
467
 
 
468
static int db1close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
 
469
        /*@modifies dbi, fileSystem @*/
 
470
{
 
471
    rpmdb rpmdb = dbi->dbi_rpmdb;
 
472
    const char * base = db1basename(dbi->dbi_rpmtag);
 
473
    const char * urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
 
474
    const char * fn;
 
475
    int rc = 0;
 
476
 
 
477
    (void) urlPath(urlfn, &fn);
 
478
 
 
479
    if (dbi->dbi_db) {
 
480
        if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
 
481
            FD_t pkgs = dbi->dbi_db;
 
482
            rc = Fclose(pkgs);
 
483
        }
 
484
#ifdef  DYING
 
485
        else {
 
486
            DB * db = dbi->dbi_db;
 
487
            rc = db->close(db);
 
488
            rc = cvtdberr(dbi, "db->close", rc, _debug);
 
489
        }
 
490
#else
 
491
        else
 
492
            rc = EINVAL;
 
493
#endif
 
494
        dbi->dbi_db = NULL;
 
495
    }
 
496
 
 
497
    rpmMessage(RPMMESS_DEBUG, _("closed  db file        %s\n"), urlfn);
 
498
    /* Remove temporary databases */
 
499
    if (dbi->dbi_temporary) {
 
500
        rpmMessage(RPMMESS_DEBUG, _("removed db file        %s\n"), urlfn);
 
501
        (void) unlink(fn);
 
502
    }
 
503
 
 
504
    dbi = db3Free(dbi);
 
505
    base = _free(base);
 
506
    urlfn = _free(urlfn);
 
507
    return rc;
 
508
}
 
509
 
 
510
static int db1open(/*@keep@*/ rpmdb rpmdb, int rpmtag,
 
511
        /*@out@*/ dbiIndex * dbip)
 
512
        /*@modifies *dbip, fileSystem @*/
 
513
{
 
514
    /*@-nestedextern@*/
 
515
    extern struct _dbiVec db1vec;
 
516
    /*@=nestedextern@*/
 
517
    const char * base = NULL;
 
518
    const char * urlfn = NULL;
 
519
    const char * fn = NULL;
 
520
    dbiIndex dbi = NULL;
 
521
    int rc = 0;
 
522
 
 
523
    if (dbip)
 
524
        *dbip = NULL;
 
525
    if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
 
526
        return EFAULT;
 
527
    dbi->dbi_api = DB_VERSION_MAJOR;
 
528
 
 
529
    base = db1basename(rpmtag);
 
530
    urlfn = rpmGenPath(rpmdb->db_root, rpmdb->db_home, base);
 
531
    (void) urlPath(urlfn, &fn);
 
532
    if (!(fn && *fn != '\0')) {
 
533
        rpmError(RPMERR_DBOPEN, _("bad db file %s\n"), urlfn);
 
534
        rc = EFAULT;
 
535
        goto exit;
 
536
    }
 
537
 
 
538
    rpmMessage(RPMMESS_DEBUG, _("opening db file        %s mode 0x%x\n"),
 
539
                urlfn, dbi->dbi_mode);
 
540
 
 
541
    if (dbi->dbi_rpmtag == RPMDBI_PACKAGES) {
 
542
        FD_t pkgs;
 
543
 
 
544
        pkgs = fadOpen(fn, dbi->dbi_mode, dbi->dbi_perms);
 
545
        if (Ferror(pkgs)) {
 
546
            rc = errno;         /* XXX check errno validity */
 
547
            goto exit;
 
548
        }
 
549
 
 
550
        /* XXX HACK: fcntl lock if db3 (DB_INIT_CDB | DB_INIT_LOCK) specified */
 
551
        if (dbi->dbi_lockdbfd || (dbi->dbi_eflags & 0x30)) {
 
552
            struct flock l;
 
553
 
 
554
            l.l_whence = 0;
 
555
            l.l_start = 0;
 
556
            l.l_len = 0;
 
557
            l.l_type = (dbi->dbi_mode & O_RDWR) ? F_WRLCK : F_RDLCK;
 
558
 
 
559
            if (Fcntl(pkgs, F_SETLK, (void *) &l)) {
 
560
                rc = errno;     /* XXX check errno validity */
 
561
                rpmError(RPMERR_FLOCK, _("cannot get %s lock on database\n"),
 
562
                    ((dbi->dbi_mode & O_RDWR) ? _("exclusive") : _("shared")));
 
563
                goto exit;
 
564
            }
 
565
        }
 
566
 
 
567
        dbi->dbi_db = pkgs;
 
568
    }
 
569
#ifdef  DYING
 
570
    else {
 
571
        void * dbopeninfo = NULL;
 
572
        int dbimode = dbi->dbi_mode;
 
573
 
 
574
        if (dbi->dbi_temporary)
 
575
            dbimode |= (O_CREAT | O_RDWR);
 
576
 
 
577
        dbi->dbi_db = dbopen(fn, dbimode, dbi->dbi_perms,
 
578
                db3_to_dbtype(dbi->dbi_type), dbopeninfo);
 
579
        if (dbi->dbi_db == NULL) rc = errno;
 
580
    }
 
581
#else
 
582
    else
 
583
        rc = EINVAL;
 
584
#endif
 
585
 
 
586
exit:
 
587
    if (rc == 0 && dbi->dbi_db != NULL && dbip) {
 
588
        dbi->dbi_vec = &db1vec;
 
589
        if (dbip) *dbip = dbi;
 
590
    } else
 
591
        (void) db1close(dbi, 0);
 
592
 
 
593
    base = _free(base);
 
594
    urlfn = _free(urlfn);
 
595
 
 
596
    return rc;
 
597
}
 
598
/*@=onlytrans@*/
 
599
 
 
600
/** \ingroup db1
 
601
 */
 
602
/*@-exportheadervar@*/
 
603
struct _dbiVec db1vec = {
 
604
    DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
 
605
    db1open, db1close, db1sync, db1copen, db1cclose, db1cdel, db1cget, db1cput,
 
606
    db1ccount, db1byteswapped, db1stat
 
607
};
 
608
/*@=exportheadervar@*/