~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to libatalk/cnid/cnid_open.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: cnid_open.c,v 1.43.2.2 2003/03/19 11:50:18 didg Exp $
 
3
 *
 
4
 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
 
5
 * All Rights Reserved. See COPYRIGHT.
 
6
 *
 
7
 * CNID database support. 
 
8
 *
 
9
 * here's the deal:
 
10
 *  1) afpd already caches did's. 
 
11
 *  2) the database stores cnid's as both did/name and dev/ino pairs. 
 
12
 *  3) RootInfo holds the value of the NextID.
 
13
 *  4) the cnid database gets called in the following manner --
 
14
 *     start a database:
 
15
 *     cnid = cnid_open(root_dir);
 
16
 *
 
17
 *     allocate a new id: 
 
18
 *     newid = cnid_add(cnid, dev, ino, parent did,
 
19
 *     name, id); id is a hint for a specific id. pass 0 if you don't
 
20
 *     care. if the id is already assigned, you won't get what you
 
21
 *     requested.
 
22
 *
 
23
 *     given an id, get a did/name and dev/ino pair.
 
24
 *     name = cnid_get(cnid, &id); given an id, return the corresponding
 
25
 *     info.
 
26
 *     return code = cnid_delete(cnid, id); delete an entry. 
 
27
 *
 
28
 * with AFP, CNIDs 0-2 have special meanings. here they are:
 
29
 * 0 -- invalid cnid
 
30
 * 1 -- parent of root directory (handled by afpd) 
 
31
 * 2 -- root directory (handled by afpd)
 
32
 *
 
33
 * CNIDs 4-16 are reserved according to page 31 of the AFP 3.0 spec so, 
 
34
 * CNID_START begins at 17.
 
35
 */
 
36
 
 
37
#ifdef HAVE_CONFIG_H
 
38
#include "config.h"
 
39
#endif /* HAVE_CONFIG_H */
 
40
 
 
41
#ifdef CNID_DB
 
42
#include <errno.h>
 
43
#include <stdlib.h>
 
44
#include <string.h>
 
45
#ifdef HAVE_UNISTD_H
 
46
#include <unistd.h>
 
47
#endif /* HAVE_UNISTD_H */
 
48
#ifdef HAVE_FCNTL_H
 
49
#include <fcntl.h>
 
50
#endif /* HAVE_FCNTL_H */
 
51
#include <sys/param.h>
 
52
#include <sys/stat.h>
 
53
#include <atalk/logger.h>
 
54
#ifdef HAVE_SYS_TIME_H
 
55
#include <sys/time.h>
 
56
#endif /* HAVE_SYS_TIME_H */
 
57
 
 
58
#include <db.h>
 
59
 
 
60
#include <atalk/adouble.h>
 
61
#include <atalk/cnid.h>
 
62
#include <atalk/util.h>
 
63
 
 
64
#include "cnid_private.h"
 
65
 
 
66
#ifndef MIN
 
67
#define MIN(a, b)  ((a) < (b) ? (a) : (b))
 
68
#endif /* ! MIN */
 
69
 
 
70
#define DBHOME        ".AppleDB"
 
71
#define DBCNID        "cnid.db"
 
72
#define DBDEVINO      "devino.db"
 
73
#define DBDIDNAME     "didname.db"   /* did/full name mapping */
 
74
#define DBSHORTNAME   "shortname.db" /* did/8+3 mapping */
 
75
#define DBMACNAME     "macname.db"   /* did/31 mapping */
 
76
#define DBMANGLE      "mangle.db"    /* filename mangling */
 
77
#define DBLONGNAME    "longname.db"  /* did/unicode mapping */
 
78
#define DBLOCKFILE    "cnid.lock"
 
79
#define DBRECOVERFILE "cnid.dbrecover"
 
80
#define DBCLOSEFILE   "cnid.close"
 
81
 
 
82
#define DBHOMELEN    8
 
83
#define DBLEN        10
 
84
 
 
85
/* we version the did/name database so that we can change the format
 
86
 * if necessary. the key is in the form of a did/name pair. in this case,
 
87
 * we use 0/0. */
 
88
#define DBVERSION_KEY    "\0\0\0\0\0"
 
89
#define DBVERSION_KEYLEN 5
 
90
#define DBVERSION1       0x00000001U
 
91
#define DBVERSION        DBVERSION1
 
92
 
 
93
#ifdef CNID_DB_CDB
 
94
#define DBOPTIONS    (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL)
 
95
#else /* !CNID_DB_CDB */
 
96
#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
 
97
#define DBOPTIONS    (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
 
98
DB_INIT_LOG | DB_INIT_TXN)
 
99
#else /* DB_VERSION_MINOR < 1 */
 
100
/*#define DBOPTIONS    (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
 
101
DB_INIT_LOG | DB_INIT_TXN | DB_TXN_NOSYNC)*/
 
102
#define DBOPTIONS    (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \
 
103
DB_INIT_LOG | DB_INIT_TXN)
 
104
#endif /* DB_VERSION_MINOR */
 
105
#endif /* CNID_DB_CDB */
 
106
 
 
107
#ifndef CNID_DB_CDB
 
108
/* Let's try and use the youngest lock detector if present.
 
109
 * If we can't do that, then let BDB use its default deadlock detector. */
 
110
#if defined DB_LOCK_YOUNGEST
 
111
#define DEAD_LOCK_DETECT DB_LOCK_YOUNGEST
 
112
#else /* DB_LOCK_YOUNGEST */
 
113
#define DEAD_LOCK_DETECT DB_LOCK_DEFAULT
 
114
#endif /* DB_LOCK_YOUNGEST */
 
115
#endif /* CNID_DB_CDB */
 
116
 
 
117
#define MAXITER     0xFFFF /* maximum number of simultaneously open CNID
 
118
* databases. */
 
119
 
 
120
/* -----------------------
 
121
 * bandaid for LanTest performance pb. for now not used, cf. ifdef 0 below
 
122
*/
 
123
static int my_yield(void) 
 
124
{
 
125
    struct timeval t;
 
126
    int ret;
 
127
 
 
128
    t.tv_sec = 0;
 
129
    t.tv_usec = 1000;
 
130
    ret = select(0, NULL, NULL, NULL, &t);
 
131
    return 0;
 
132
}
 
133
 
 
134
/* --------------- */
 
135
static int  my_open(DB *p, const char *f, const char *d, DBTYPE t, u_int32_t flags, int mode)
 
136
{
 
137
#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
 
138
    return p->open(p, NULL, f, d, t, flags, mode);
 
139
#else
 
140
    return p->open(p,       f, d, t, flags, mode);
 
141
#endif
 
142
}
 
143
 
 
144
/* --------------- */
 
145
/* the first compare that's always done. */
 
146
static __inline__ int compare_did(const DBT *a, const DBT *b)
 
147
{
 
148
    u_int32_t dida, didb;
 
149
 
 
150
    memcpy(&dida, a->data, sizeof(dida));
 
151
    memcpy(&didb, b->data, sizeof(didb));
 
152
    return dida - didb;
 
153
}
 
154
 
 
155
/* sort did's and then names. this is for unix paths.
 
156
 * i.e., did/unixname lookups. */
 
157
#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
 
158
static int compare_unix(DB *db, const DBT *a, const DBT *b)
 
159
#else /* DB_VERSION_MINOR < 1 */
 
160
static int compare_unix(const DBT *a, const DBT *b)
 
161
#endif /* DB_VERSION_MINOR */
 
162
{
 
163
    u_int8_t *sa, *sb;
 
164
    int len, ret;
 
165
 
 
166
    /* sort by did */
 
167
    if ((ret = compare_did(a, b)))
 
168
        return ret;
 
169
 
 
170
    sa = (u_int8_t *) a->data + 4; /* shift past did */
 
171
    sb = (u_int8_t *) b->data + 4;
 
172
    for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++)
 
173
        if ((ret = (*sa - *sb)))
 
174
            return ret; /* sort by lexical ordering */
 
175
 
 
176
    return a->size - b->size; /* sort by length */
 
177
}
 
178
 
 
179
/* sort did's and then names. this is for macified paths (i.e.,
 
180
 * did/macname, and did/shortname. i think did/longname needs a
 
181
 * unicode table to work. also, we can't use strdiacasecmp as that
 
182
 * returns a match if a < b. */
 
183
#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
 
184
static int compare_mac(DB *db, const DBT *a, const DBT *b)
 
185
#else /* DB_VERSION_MINOR < 1 */
 
186
static int compare_mac(const DBT *a, const DBT *b)
 
187
#endif /* DB_VERSION_MINOR */
 
188
{
 
189
    u_int8_t *sa, *sb;
 
190
    int len, ret;
 
191
 
 
192
    /* sort by did */
 
193
    if ((ret = compare_did(a, b)))
 
194
        return ret;
 
195
 
 
196
    sa = (u_int8_t *) a->data + 4;
 
197
    sb = (u_int8_t *) b->data + 4;
 
198
    for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++)
 
199
        if ((ret = (_diacasemap[*sa] - _diacasemap[*sb])))
 
200
            return ret; /* sort by lexical ordering */
 
201
 
 
202
    return a->size - b->size; /* sort by length */
 
203
}
 
204
 
 
205
 
 
206
/* for unicode names -- right now it's the same as compare_mac. */
 
207
#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
 
208
static int compare_unicode(DB *db, const DBT *a, const DBT *b)
 
209
#else /* DB_VERSION_MINOR < 1 */
 
210
static int compare_unicode(const DBT *a, const DBT *b)
 
211
#endif /* DB_VERSION_MINOR */
 
212
{
 
213
#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
 
214
    return compare_mac(db,a,b);
 
215
#else /* DB_VERSION_MINOR < 1 */
 
216
    return compare_mac(a,b);
 
217
#endif /* DB_VERSION_MINOR */
 
218
}
 
219
 
 
220
void *cnid_open(const char *dir, mode_t mask) {
 
221
    struct stat st;
 
222
#ifndef CNID_DB_CDB
 
223
    struct flock lock;
 
224
#endif /* CNID_DB_CDB */
 
225
char path[MAXPATHLEN + 1];
 
226
    CNID_private *db;
 
227
    DBT key, data;
 
228
    DB_TXN *tid;
 
229
    int open_flag, len;
 
230
    int rc;
 
231
 
 
232
    if (!dir) {
 
233
        return NULL;
 
234
    }
 
235
 
 
236
    /* this checks .AppleDB */
 
237
    if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
 
238
        LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", dir);
 
239
        return NULL;
 
240
    }
 
241
 
 
242
    if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
 
243
        LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
 
244
        return NULL;
 
245
    }
 
246
 
 
247
    db->magic = CNID_DB_MAGIC;
 
248
 
 
249
    strcpy(path, dir);
 
250
    if (path[len - 1] != '/') {
 
251
        strcat(path, "/");
 
252
        len++;
 
253
    }
 
254
 
 
255
    strcpy(path + len, DBHOME);
 
256
    if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
 
257
        LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path);
 
258
        goto fail_adouble;
 
259
    }
 
260
 
 
261
#ifndef CNID_DB_CDB
 
262
    lock.l_type = F_WRLCK;
 
263
    lock.l_whence = SEEK_SET;
 
264
    /* Make sure cnid.lock goes in .AppleDB. */
 
265
    strcat(path, "/");
 
266
    len++;
 
267
 
 
268
    /* Search for a byte lock.  This allows us to cleanup the log files
 
269
     * at cnid_close() in a clean fashion.
 
270
     *
 
271
     * NOTE: This won't work if multiple volumes for the same user refer
 
272
     * to the sahe directory. */
 
273
    strcat(path, DBLOCKFILE);
 
274
    strcpy(db->lock_file, path);
 
275
    if ((db->lockfd = open(path, O_RDWR | O_CREAT, 0666 & ~mask)) > -1) {
 
276
        lock.l_start = 0;
 
277
        lock.l_len = 1;
 
278
        while (fcntl(db->lockfd, F_SETLK, &lock) < 0) {
 
279
            if (++lock.l_start > MAXITER) {
 
280
                LOG(log_error, logtype_default, "cnid_open: Cannot establish logfile cleanup for database environment %s lock (lock failed)", path);
 
281
                close(db->lockfd);
 
282
                db->lockfd = -1;
 
283
                break;
 
284
            }
 
285
        }
 
286
    }
 
287
    else {
 
288
        LOG(log_error, logtype_default, "cnid_open: Cannot establish logfile cleanup lock for database environment %s (open() failed)", path);
 
289
    }
 
290
#endif /* CNID_DB_CDB */
 
291
 
 
292
    path[len + DBHOMELEN] = '\0';
 
293
    open_flag = DB_CREATE;
 
294
 
 
295
    /* We need to be able to open the database environment with full
 
296
     * transaction, logging, and locking support if we ever hope to 
 
297
     * be a true multi-acess file server. */
 
298
    if ((rc = db_env_create(&db->dbenv, 0)) != 0) {
 
299
        LOG(log_error, logtype_default, "cnid_open: db_env_create: %s", db_strerror(rc));
 
300
        goto fail_lock;
 
301
    }
 
302
 
 
303
#ifndef CNID_DB_CDB
 
304
    /* Setup internal deadlock detection. */
 
305
    if ((rc = db->dbenv->set_lk_detect(db->dbenv, DEAD_LOCK_DETECT)) != 0) {
 
306
        LOG(log_error, logtype_default, "cnid_open: set_lk_detect: %s", db_strerror(rc));
 
307
        goto fail_lock;
 
308
    }
 
309
#endif /* CNID_DB_CDB */
 
310
 
 
311
#ifndef CNID_DB_CDB
 
312
#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
 
313
#if 0
 
314
    /* Take care of setting the DB_TXN_NOSYNC flag in db3 > 3.1.x. */
 
315
    if ((rc = db->dbenv->set_flags(db->dbenv, DB_TXN_NOSYNC, 1)) != 0) {
 
316
        LOG(log_error, logtype_default, "cnid_open: set_flags: %s", db_strerror(rc));
 
317
        goto fail_lock;
 
318
    }
 
319
#endif
 
320
#endif /* DB_VERSION_MINOR > 1 */
 
321
#endif /* CNID_DB_CDB */
 
322
 
 
323
    /* Open the database environment. */
 
324
    if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666 & ~mask)) != 0) {
 
325
        if (rc == DB_RUNRECOVERY) {
 
326
            /* This is the mother of all errors.  We _must_ fail here. */
 
327
            LOG(log_error, logtype_default, "cnid_open: CATASTROPHIC ERROR opening database environment %s.  Run db_recovery -c immediately", path);
 
328
            goto fail_lock;
 
329
        }
 
330
 
 
331
        /* We can't get a full transactional environment, so multi-access
 
332
         * is out of the question.  Let's assume a read-only environment,
 
333
         * and try to at least get a shared memory pool. */
 
334
        if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666 & ~mask)) != 0) {
 
335
            /* Nope, not a MPOOL, either.  Last-ditch effort: we'll try to
 
336
             * open the environment with no flags. */
 
337
            if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666 & ~mask)) != 0) {
 
338
                LOG(log_error, logtype_default, "cnid_open: dbenv->open of %s failed: %s",
 
339
                    path, db_strerror(rc));
 
340
                goto fail_lock;
 
341
            }
 
342
        }
 
343
        db->flags |= CNIDFLAG_DB_RO;
 
344
        open_flag = DB_RDONLY;
 
345
        LOG(log_info, logtype_default, "cnid_open: Obtained read-only database environment %s", path);
 
346
    }
 
347
 
 
348
    /* did/name reverse mapping.  We use a BTree for this one. */
 
349
    if ((rc = db_create(&db->db_didname, db->dbenv, 0)) != 0) {
 
350
        LOG(log_error, logtype_default, "cnid_open: Failed to create did/name database: %s",
 
351
            db_strerror(rc));
 
352
        goto fail_appinit;
 
353
    }
 
354
 
 
355
    /*db->db_didname->set_bt_compare(db->db_didname, &compare_unix);*/
 
356
    if ((rc = my_open(db->db_didname, DBDIDNAME, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
 
357
        LOG(log_error, logtype_default, "cnid_open: Failed to open did/name database: %s",
 
358
            db_strerror(rc));
 
359
        goto fail_appinit;
 
360
    }
 
361
 
 
362
    /* Check for version.  This way we can update the database if we need
 
363
     * to change the format in any way. */
 
364
    memset(&key, 0, sizeof(key));
 
365
    memset(&data, 0, sizeof(data));
 
366
    key.data = DBVERSION_KEY;
 
367
    key.size = DBVERSION_KEYLEN;
 
368
 
 
369
#ifdef CNID_DB_CDB
 
370
    if ((rc = db->db_didname->get(db->db_didname, NULL, &key, &data, 0)) != 0) {
 
371
        int ret;
 
372
        {
 
373
            u_int32_t version = htonl(DBVERSION);
 
374
 
 
375
            data.data = &version;
 
376
            data.size = sizeof(version);
 
377
        }
 
378
        if ((ret = db->db_didname->put(db->db_didname, NULL, &key, &data,
 
379
                                       DB_NOOVERWRITE))) {
 
380
            LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s",
 
381
                db_strerror(ret));
 
382
            goto fail_appinit;
 
383
        }
 
384
    }
 
385
#else /* CNID_DB_CDB */
 
386
dbversion_retry:
 
387
    if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
 
388
        LOG(log_error, logtype_default, "cnid_open: txn_begin: failed to check db version: %s",
 
389
            db_strerror(rc));
 
390
        goto fail_appinit;
 
391
    }
 
392
 
 
393
    while ((rc = db->db_didname->get(db->db_didname, tid, &key, &data, DB_RMW))) {
 
394
        int ret;
 
395
        switch (rc) {
 
396
        case DB_LOCK_DEADLOCK:
 
397
            if ((ret = txn_abort(tid)) != 0) {
 
398
                LOG(log_error, logtype_default, "cnid_open: txn_abort: %s", db_strerror(ret));
 
399
                goto fail_appinit;
 
400
            }
 
401
            goto dbversion_retry;
 
402
        case DB_NOTFOUND:
 
403
            {
 
404
                u_int32_t version = htonl(DBVERSION);
 
405
 
 
406
                data.data = &version;
 
407
                data.size = sizeof(version);
 
408
            }
 
409
 
 
410
            if ((ret = db->db_didname->put(db->db_didname, tid, &key, &data,
 
411
                                           DB_NOOVERWRITE))) {
 
412
                if (ret == DB_LOCK_DEADLOCK) {
 
413
                    if ((ret = txn_abort(tid)) != 0) {
 
414
                        LOG(log_error, logtype_default, "cnid_open: txn_abort: %s",
 
415
                            db_strerror(ret));
 
416
                        goto fail_appinit;
 
417
                    }
 
418
                    goto dbversion_retry;
 
419
                }
 
420
                else if (ret == DB_RUNRECOVERY) {
 
421
                    /* At this point, we don't care if the transaction aborts
 
422
                    * successfully or not. */
 
423
                    txn_abort(tid);
 
424
                    LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s",
 
425
                        db_strerror(ret));
 
426
                    goto fail_appinit;
 
427
                }
 
428
            }
 
429
            break; /* while loop */
 
430
        default:
 
431
            txn_abort(tid);
 
432
            LOG(log_error, logtype_default, "cnid_open: Failed to check db version: %s",
 
433
                db_strerror(rc));
 
434
            goto fail_appinit;
 
435
        }
 
436
    }
 
437
 
 
438
    if ((rc = txn_commit(tid, 0)) != 0) {
 
439
        LOG(log_error, logtype_default, "cnid_open: Failed to commit db version: %s",
 
440
            db_strerror(rc));
 
441
        goto fail_appinit;
 
442
    }
 
443
#endif /* CNID_DB_CDB */
 
444
 
 
445
    /* TODO In the future we might check for version number here. */
 
446
#if 0
 
447
    memcpy(&version, data.data, sizeof(version));
 
448
    if (version != ntohl(DBVERSION)) {
 
449
        /* Do stuff here. */
 
450
    }
 
451
#endif /* 0 */
 
452
 
 
453
#ifdef EXTENDED_DB
 
454
    /* did/macname (31 character) mapping.  Use a BTree for this one. */
 
455
    if ((rc = db_create(&db->db_macname, db->dbenv, 0)) != 0) {
 
456
        LOG(log_error, logtype_default, "cnid_open: Failed to create did/macname database: %s",
 
457
            db_strerror(rc));
 
458
        goto fail_appinit;
 
459
    }
 
460
 
 
461
    db->db_macname->set_bt_compare(db->db_macname, &compare_mac);
 
462
    if ((rc = my_open(db->db_macname, DBMACNAME, NULL, DB_BTREE, open_flag, 0666 & ~mask))) {
 
463
        LOG(log_error, logtype_default, "cnid_open: Failed to open did/macname database: %s",
 
464
            db_strerror(rc));
 
465
        goto fail_appinit;
 
466
    }
 
467
 
 
468
    /* did/shortname (DOS 8.3) mapping.  Use a BTree for this one. */
 
469
    if ((rc = db_create(&db->db_shortname, db->dbenv, 0)) != 0) {
 
470
        LOG(log_error, logtype_default, "cnid_open: Failed to create did/shortname database: %s",
 
471
            db_strerror(rc));
 
472
        goto fail_appinit;
 
473
    }
 
474
 
 
475
    db->db_shortname->set_bt_compare(db->db_shortname, &compare_mac);
 
476
    if ((rc = my_open(db->db_shortname, DBSHORTNAME, NULL, DB_BTREE, open_flag, 0666 & ~mask))) {
 
477
        LOG(log_error, logtype_default, "cnid_open: Failed to open did/shortname database: %s",
 
478
            db_strerror(rc));
 
479
        goto fail_appinit;
 
480
    }
 
481
 
 
482
    /* did/longname (Unicode) mapping.  Use a BTree for this one. */
 
483
    if ((rc = db_create(&db->db_longname, db->dbenv, 0)) != 0) {
 
484
        LOG(log_error, logtype_default, "cnid_open: Failed to create did/longname database: %s",
 
485
            db_strerror(rc));
 
486
        goto fail_appinit;
 
487
    }
 
488
 
 
489
    db->db_longname->set_bt_compare(db->db_longname, &compare_unicode);
 
490
    if ((rc = my_open(db->db_longname, DBLONGNAME, NULL, DB_BTREE, open_flag, 0666 & ~mask))) {
 
491
        LOG(log_error, logtype_default, "cnid_open: Failed to open did/longname database: %s",
 
492
            db_strerror(rc));
 
493
        goto fail_appinit;
 
494
    }
 
495
#endif /* EXTENDED_DB */
 
496
 
 
497
    /* dev/ino reverse mapping.  Use a hash for this one. */
 
498
    if ((rc = db_create(&db->db_devino, db->dbenv, 0)) != 0) {
 
499
        LOG(log_error, logtype_default, "cnid_open: Failed to create dev/ino database: %s",
 
500
            db_strerror(rc));
 
501
        goto fail_appinit;
 
502
    }
 
503
 
 
504
    if ((rc = my_open(db->db_devino, DBDEVINO, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
 
505
        LOG(log_error, logtype_default, "cnid_open: Failed to open devino database: %s",
 
506
            db_strerror(rc));
 
507
        goto fail_appinit;
 
508
    }
 
509
 
 
510
    /* Main CNID database.  Use a hash for this one. */
 
511
    if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) {
 
512
        LOG(log_error, logtype_default, "cnid_open: Failed to create cnid database: %s",
 
513
            db_strerror(rc));
 
514
        goto fail_appinit;
 
515
    }
 
516
 
 
517
    if ((rc = my_open(db->db_cnid, DBCNID, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
 
518
        LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s",
 
519
            db_strerror(rc));
 
520
        goto fail_appinit;
 
521
    }
 
522
 
 
523
#ifdef FILE_MANGLING
 
524
    /* filename mangling database.  Use a hash for this one. */
 
525
    if ((rc = db_create(&db->db_mangle, db->dbenv, 0)) != 0) {
 
526
        LOG(log_error, logtype_default, "cnid_open: Failed to create mangle database: %s", db_strerror(rc));
 
527
        goto fail_appinit;
 
528
    }
 
529
 
 
530
    if ((rc = my_open(db->db_mangle, DBMANGLE, NULL, DB_HASH, open_flag, 0666 & ~mask))) {
 
531
        LOG(log_error, logtype_default, "cnid_open: Failed to open mangle database: %s", db_strerror(rc));
 
532
        goto fail_appinit;
 
533
    }
 
534
#endif /* FILE_MANGLING */
 
535
 
 
536
    /* Print out the version of BDB we're linked against. */
 
537
    LOG(log_info, logtype_default, "CNID DB initialized using %s", db_version(NULL, NULL, NULL));
 
538
#if 0
 
539
    db_env_set_func_yield(my_yield);
 
540
#endif
 
541
    return db;
 
542
 
 
543
fail_appinit:
 
544
    if (db->db_didname) db->db_didname->close(db->db_didname, 0);
 
545
    if (db->db_devino)  db->db_devino->close(db->db_devino, 0);
 
546
    if (db->db_cnid)    db->db_cnid->close(db->db_cnid, 0);
 
547
#ifdef EXTENDED_DB
 
548
    if (db->db_macname)   db->db_macname->close(db->db_macname, 0);
 
549
    if (db->db_shortname) db->db_shortname->close(db->db_shortname, 0);
 
550
    if (db->db_longname)  db->db_longname->close(db->db_longname, 0);
 
551
#endif /* EXTENDED_DB */
 
552
    LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment");
 
553
    db->dbenv->close(db->dbenv, 0);
 
554
 
 
555
fail_lock:
 
556
#ifndef CNID_DB_CDB
 
557
    if (db->lockfd > -1) {
 
558
        close(db->lockfd);
 
559
        (void)remove(db->lock_file);
 
560
    }
 
561
#endif /* CNID_DB_CDB */
 
562
 
 
563
fail_adouble:
 
564
 
 
565
fail_db:
 
566
    free(db);
 
567
    return NULL;
 
568
}
 
569
#endif /* CNID_DB */
 
570
 
 
571