]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid_open.c
Change all references to db3/DB3 to BDB. We now support Berkeley DB
[netatalk.git] / libatalk / cnid / cnid_open.c
1 /*
2  * $Id: cnid_open.c,v 1.49 2003-01-04 21:41:49 jmarcus 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 /* the first compare that's always done. */
121 static __inline__ int compare_did(const DBT *a, const DBT *b)
122 {
123     u_int32_t dida, didb;
124
125     memcpy(&dida, a->data, sizeof(dida));
126     memcpy(&didb, b->data, sizeof(didb));
127     return dida - didb;
128 }
129
130 /* sort did's and then names. this is for unix paths.
131  * i.e., did/unixname lookups. */
132 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
133 static int compare_unix(DB *db, const DBT *a, const DBT *b)
134 #else /* DB_VERSION_MINOR < 1 */
135 static int compare_unix(const DBT *a, const DBT *b)
136 #endif /* DB_VERSION_MINOR */
137 {
138     u_int8_t *sa, *sb;
139     int len, ret;
140
141     /* sort by did */
142     if ((ret = compare_did(a, b)))
143         return ret;
144
145     sa = (u_int8_t *) a->data + 4; /* shift past did */
146     sb = (u_int8_t *) b->data + 4;
147     for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++)
148         if ((ret = (*sa - *sb)))
149             return ret; /* sort by lexical ordering */
150
151     return a->size - b->size; /* sort by length */
152 }
153
154 /* sort did's and then names. this is for macified paths (i.e.,
155  * did/macname, and did/shortname. i think did/longname needs a
156  * unicode table to work. also, we can't use strdiacasecmp as that
157  * returns a match if a < b. */
158 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
159 static int compare_mac(DB *db, const DBT *a, const DBT *b)
160 #else /* DB_VERSION_MINOR < 1 */
161 static int compare_mac(const DBT *a, const DBT *b)
162 #endif /* DB_VERSION_MINOR */
163 {
164     u_int8_t *sa, *sb;
165     int len, ret;
166
167     /* sort by did */
168     if ((ret = compare_did(a, b)))
169         return ret;
170
171     sa = (u_int8_t *) a->data + 4;
172     sb = (u_int8_t *) b->data + 4;
173     for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++)
174         if ((ret = (_diacasemap[*sa] - _diacasemap[*sb])))
175             return ret; /* sort by lexical ordering */
176
177     return a->size - b->size; /* sort by length */
178 }
179
180
181 /* for unicode names -- right now it's the same as compare_mac. */
182 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
183 static int compare_unicode(DB *db, const DBT *a, const DBT *b)
184 #else /* DB_VERSION_MINOR < 1 */
185 static int compare_unicode(const DBT *a, const DBT *b)
186 #endif /* DB_VERSION_MINOR */
187 {
188 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
189     return compare_mac(db,a,b);
190 #else /* DB_VERSION_MINOR < 1 */
191     return compare_mac(a,b);
192 #endif /* DB_VERSION_MINOR */
193 }
194
195 void *cnid_open(const char *dir, mode_t mask) {
196     struct stat st;
197 #ifndef CNID_DB_CDB
198     struct flock lock;
199 #endif /* CNID_DB_CDB */
200 char path[MAXPATHLEN + 1];
201     CNID_private *db;
202     DBT key, data;
203     DB_TXN *tid;
204     int open_flag, len;
205     int rc;
206
207     if (!dir) {
208         return NULL;
209     }
210
211     /* this checks .AppleDB */
212     if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
213         LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", dir);
214         return NULL;
215     }
216
217     if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
218         LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
219         return NULL;
220     }
221
222     db->magic = CNID_DB_MAGIC;
223
224     strcpy(path, dir);
225     if (path[len - 1] != '/') {
226         strcat(path, "/");
227         len++;
228     }
229
230     strcpy(path + len, DBHOME);
231     if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
232         LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path);
233         goto fail_adouble;
234     }
235
236 #ifndef CNID_DB_CDB
237     lock.l_type = F_WRLCK;
238     lock.l_whence = SEEK_SET;
239     /* Make sure cnid.lock goes in .AppleDB. */
240     strcat(path, "/");
241     len++;
242
243     /* Search for a byte lock.  This allows us to cleanup the log files
244      * at cnid_close() in a clean fashion.
245      *
246      * NOTE: This won't work if multiple volumes for the same user refer
247      * to the sahe directory. */
248     strcat(path, DBLOCKFILE);
249     strcpy(db->lock_file, path);
250     if ((db->lockfd = open(path, O_RDWR | O_CREAT, 0666 & ~mask)) > -1) {
251         lock.l_start = 0;
252         lock.l_len = 1;
253         while (fcntl(db->lockfd, F_SETLK, &lock) < 0) {
254             if (++lock.l_start > MAXITER) {
255                 LOG(log_error, logtype_default, "cnid_open: Cannot establish logfile cleanup for database environment %s lock (lock failed)", path);
256                 close(db->lockfd);
257                 db->lockfd = -1;
258                 break;
259             }
260         }
261     }
262     else {
263         LOG(log_error, logtype_default, "cnid_open: Cannot establish logfile cleanup lock for database environment %s (open() failed)", path);
264     }
265 #endif /* CNID_DB_CDB */
266
267     path[len + DBHOMELEN] = '\0';
268     open_flag = DB_CREATE;
269
270     /* We need to be able to open the database environment with full
271      * transaction, logging, and locking support if we ever hope to 
272      * be a true multi-acess file server. */
273     if ((rc = db_env_create(&db->dbenv, 0)) != 0) {
274         LOG(log_error, logtype_default, "cnid_open: db_env_create: %s", db_strerror(rc));
275         goto fail_lock;
276     }
277
278 #ifndef CNID_DB_CDB
279     /* Setup internal deadlock detection. */
280     if ((rc = db->dbenv->set_lk_detect(db->dbenv, DEAD_LOCK_DETECT)) != 0) {
281         LOG(log_error, logtype_default, "cnid_open: set_lk_detect: %s", db_strerror(rc));
282         goto fail_lock;
283     }
284 #endif /* CNID_DB_CDB */
285
286 #ifndef CNID_DB_CDB
287 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1)
288 #if 0
289     /* Take care of setting the DB_TXN_NOSYNC flag in db3 > 3.1.x. */
290     if ((rc = db->dbenv->set_flags(db->dbenv, DB_TXN_NOSYNC, 1)) != 0) {
291         LOG(log_error, logtype_default, "cnid_open: set_flags: %s", db_strerror(rc));
292         goto fail_lock;
293     }
294 #endif
295 #endif /* DB_VERSION_MINOR > 1 */
296 #endif /* CNID_DB_CDB */
297
298     /* Open the database environment. */
299     if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666 & ~mask)) != 0) {
300         if (rc == DB_RUNRECOVERY) {
301             /* This is the mother of all errors.  We _must_ fail here. */
302             LOG(log_error, logtype_default, "cnid_open: CATASTROPHIC ERROR opening database environment %s.  Run db_recovery -c immediately", path);
303             goto fail_lock;
304         }
305
306         /* We can't get a full transactional environment, so multi-access
307          * is out of the question.  Let's assume a read-only environment,
308          * and try to at least get a shared memory pool. */
309         if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666 & ~mask)) != 0) {
310             /* Nope, not a MPOOL, either.  Last-ditch effort: we'll try to
311              * open the environment with no flags. */
312             if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666 & ~mask)) != 0) {
313                 LOG(log_error, logtype_default, "cnid_open: dbenv->open of %s failed: %s",
314                     path, db_strerror(rc));
315                 goto fail_lock;
316             }
317         }
318         db->flags |= CNIDFLAG_DB_RO;
319         open_flag = DB_RDONLY;
320         LOG(log_info, logtype_default, "cnid_open: Obtained read-only database environment %s", path);
321     }
322
323     /* did/name reverse mapping.  We use a BTree for this one. */
324     if ((rc = db_create(&db->db_didname, db->dbenv, 0)) != 0) {
325         LOG(log_error, logtype_default, "cnid_open: Failed to create did/name database: %s",
326             db_strerror(rc));
327         goto fail_appinit;
328     }
329
330     /*db->db_didname->set_bt_compare(db->db_didname, &compare_unix);*/
331 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
332     if ((rc = db->db_didname->open(db->db_didname, NULL, DBDIDNAME, NULL,
333                                    DB_HASH, open_flag | DB_AUTO_COMMIT, 0666 & ~mask))) {
334 #else
335     if ((rc = db->db_didname->open(db->db_didname, DBDIDNAME, NULL,
336                                    DB_HASH, open_flag, 0666 & ~mask))) {
337 #endif /* DB_VERSION_MAJOR >= 4 */
338         LOG(log_error, logtype_default, "cnid_open: Failed to open did/name database: %s",
339             db_strerror(rc));
340         goto fail_appinit;
341     }
342
343     /* Check for version.  This way we can update the database if we need
344      * to change the format in any way. */
345     memset(&key, 0, sizeof(key));
346     memset(&data, 0, sizeof(data));
347     key.data = DBVERSION_KEY;
348     key.size = DBVERSION_KEYLEN;
349
350 #ifdef CNID_DB_CDB
351     if ((rc = db->db_didname->get(db->db_didname, NULL, &key, &data, 0)) != 0) {
352         int ret;
353         {
354             u_int32_t version = htonl(DBVERSION);
355
356             data.data = &version;
357             data.size = sizeof(version);
358         }
359         if ((ret = db->db_didname->put(db->db_didname, NULL, &key, &data,
360                                        DB_NOOVERWRITE))) {
361             LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s",
362                 db_strerror(ret));
363             db->db_didname->close(db->db_didname, 0);
364             goto fail_appinit;
365         }
366     }
367 #else /* CNID_DB_CDB */
368 dbversion_retry:
369     if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
370         LOG(log_error, logtype_default, "cnid_open: txn_begin: failed to check db version: %s",
371             db_strerror(rc));
372         db->db_didname->close(db->db_didname, 0);
373         goto fail_appinit;
374     }
375
376     while ((rc = db->db_didname->get(db->db_didname, tid, &key, &data, DB_RMW))) {
377         int ret;
378         switch (rc) {
379         case DB_LOCK_DEADLOCK:
380             if ((ret = txn_abort(tid)) != 0) {
381                 LOG(log_error, logtype_default, "cnid_open: txn_abort: %s", db_strerror(ret));
382                 db->db_didname->close(db->db_didname, 0);
383                 goto fail_appinit;
384             }
385             goto dbversion_retry;
386         case DB_NOTFOUND:
387             {
388                 u_int32_t version = htonl(DBVERSION);
389
390                 data.data = &version;
391                 data.size = sizeof(version);
392             }
393
394             if ((ret = db->db_didname->put(db->db_didname, tid, &key, &data,
395                                            DB_NOOVERWRITE))) {
396                 if (ret == DB_LOCK_DEADLOCK) {
397                     if ((ret = txn_abort(tid)) != 0) {
398                         LOG(log_error, logtype_default, "cnid_open: txn_abort: %s",
399                             db_strerror(ret));
400                         db->db_didname->close(db->db_didname, 0);
401                         goto fail_appinit;
402                     }
403                     goto dbversion_retry;
404                 }
405                 else if (ret == DB_RUNRECOVERY) {
406                     /* At this point, we don't care if the transaction aborts
407                     * successfully or not. */
408                     txn_abort(tid);
409                     LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s",
410                         db_strerror(ret));
411                     db->db_didname->close(db->db_didname, 0);
412                     goto fail_appinit;
413                 }
414             }
415             break; /* while loop */
416         default:
417             txn_abort(tid);
418             LOG(log_error, logtype_default, "cnid_open: Failed to check db version: %s",
419                 db_strerror(rc));
420             db->db_didname->close(db->db_didname, 0);
421             goto fail_appinit;
422         }
423     }
424
425     if ((rc = txn_commit(tid, 0)) != 0) {
426         LOG(log_error, logtype_default, "cnid_open: Failed to commit db version: %s",
427             db_strerror(rc));
428         db->db_didname->close(db->db_didname, 0);
429         goto fail_appinit;
430     }
431 #endif /* CNID_DB_CDB */
432
433     /* TODO In the future we might check for version number here. */
434 #if 0
435     memcpy(&version, data.data, sizeof(version));
436     if (version != ntohl(DBVERSION)) {
437         /* Do stuff here. */
438     }
439 #endif /* 0 */
440
441 #ifdef EXTENDED_DB
442     /* did/macname (31 character) mapping.  Use a BTree for this one. */
443     if ((rc = db_create(&db->db_macname, db->dbenv, 0)) != 0) {
444         LOG(log_error, logtype_default, "cnid_open: Failed to create did/macname database: %s",
445             db_strerror(rc));
446         db->db_didname->close(db->db_didname, 0);
447         goto fail_appinit;
448     }
449
450     db->db_macname->set_bt_compare(db->db_macname, &compare_mac);
451 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
452     if ((rc = db->db_macname->open(db->db_macname, NULL, DBMACNAME, NULL, DB_BTREE, open_flag | DB_AUTO_COMMIT, 0666 & ~mask)) != 0) {
453 #else
454     if ((rc = db->db_macname->open(db->db_macname, DBMACNAME, NULL, DB_BTREE, open_flag, 0666 & ~mask)) != 0) {
455 #endif /* DB_VERSION_MAJOR >= 4 */
456         LOG(log_error, logtype_default, "cnid_open: Failed to open did/macname database: %s",
457             db_strerror(rc));
458         db->db_didname->close(db->db_didname, 0);
459         goto fail_appinit;
460     }
461
462     /* did/shortname (DOS 8.3) mapping.  Use a BTree for this one. */
463     if ((rc = db_create(&db->db_shortname, db->dbenv, 0)) != 0) {
464         LOG(log_error, logtype_default, "cnid_open: Failed to create did/shortname database: %s",
465             db_strerror(rc));
466         db->db_didname->close(db->db_didname, 0);
467         db->db_macname->close(db->db_macname, 0);
468         goto fail_appinit;
469     }
470
471     db->db_shortname->set_bt_compare(db->db_shortname, &compare_mac);
472 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
473     if ((rc = db->db_shortname->open(db->db_shortname, NULL, DBSHORTNAME, NULL, DB_BTREE, open_flag | DB_AUTO_COMMIT, 0666 & ~mask)) != 0) {
474 #else
475     if ((rc = db->db_shortname->open(db->db_shortname, DBSHORTNAME, NULL, DB_BTREE, open_flag, 0666 & ~mask)) != 0) {
476 #endif /* DB_VERSION_MAJOR >= 4 */
477         LOG(log_error, logtype_default, "cnid_open: Failed to open did/shortname database: %s",
478             db_strerror(rc));
479         db->db_didname->close(db->db_didname, 0);
480         db->db_macname->close(db->db_macname, 0);
481         goto fail_appinit;
482     }
483
484     /* did/longname (Unicode) mapping.  Use a BTree for this one. */
485     if ((rc = db_create(&db->db_longname, db->dbenv, 0)) != 0) {
486         LOG(log_error, logtype_default, "cnid_open: Failed to create did/longname database: %s",
487             db_strerror(rc));
488         db->db_didname->close(db->db_didname, 0);
489         db->db_macname->close(db->db_macname, 0);
490         db->db_shortname->close(db->db_shortname, 0);
491         goto fail_appinit;
492     }
493
494     db->db_longname->set_bt_compare(db->db_longname, &compare_unicode);
495 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
496     if ((rc = db->db_longname->open(db->db_longname, NULL, DBLONGNAME, NULL, DB_BTREE, open_flag | DB_AUTO_COMMIT, 0666 & ~mask)) != 0) {
497 #else
498     if ((rc = db->db_longname->open(db->db_longname, DBLONGNAME, NULL, DB_BTREE, open_flag, 0666 & ~mask)) != 0) {
499 #endif /* DB_VERSION_MAJOR >= 4 */
500         LOG(log_error, logtype_default, "cnid_open: Failed to open did/longname database: %s",
501             db_strerror(rc));
502         db->db_didname->close(db->db_didname, 0);
503         db->db_macname->close(db->db_macname, 0);
504         db->db_shortname->close(db->db_shortname, 0);
505         goto fail_appinit;
506     }
507 #endif /* EXTENDED_DB */
508
509     /* dev/ino reverse mapping.  Use a hash for this one. */
510     if ((rc = db_create(&db->db_devino, db->dbenv, 0)) != 0) {
511         LOG(log_error, logtype_default, "cnid_open: Failed to create dev/ino database: %s",
512             db_strerror(rc));
513         db->db_didname->close(db->db_didname, 0);
514 #ifdef EXTENDED_DB
515         db->db_macname->close(db->db_macname, 0);
516         db->db_shortname->close(db->db_shortname, 0);
517         db->db_longname->close(db->db_longname, 0);
518 #endif /* EXTENDED_DB */
519         goto fail_appinit;
520     }
521
522 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
523     if ((rc = db->db_devino->open(db->db_devino, NULL, DBDEVINO, NULL, DB_HASH, open_flag | DB_AUTO_COMMIT, 0666 & ~mask)) != 0) {
524 #else
525     if ((rc = db->db_devino->open(db->db_devino, DBDEVINO, NULL, DB_HASH, open_flag, 0666 & ~mask)) != 0) {
526 #endif /* DB_VERSION_MAJOR >= 4 */
527         LOG(log_error, logtype_default, "cnid_open: Failed to open devino database: %s",
528             db_strerror(rc));
529         db->db_didname->close(db->db_didname, 0);
530 #ifdef EXTENDED_DB
531         db->db_macname->close(db->db_macname, 0);
532         db->db_shortname->close(db->db_shortname, 0);
533         db->db_longname->close(db->db_longname, 0);
534 #endif /* EXTENDED_DB */
535         goto fail_appinit;
536     }
537
538     /* Main CNID database.  Use a hash for this one. */
539     if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) {
540         LOG(log_error, logtype_default, "cnid_open: Failed to create cnid database: %s",
541             db_strerror(rc));
542         db->db_didname->close(db->db_didname, 0);
543 #ifdef EXTENDED_DB
544         db->db_macname->close(db->db_macname, 0);
545         db->db_shortname->close(db->db_shortname, 0);
546         db->db_longname->close(db->db_longname, 0);
547 #endif /* EXTENDED_DB */
548         db->db_devino->close(db->db_devino, 0);
549         goto fail_appinit;
550     }
551
552
553 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
554     if ((rc = db->db_cnid->open(db->db_cnid, NULL, DBCNID, NULL, DB_HASH, open_flag | DB_AUTO_COMMIT, 0666 & ~mask)) != 0) {
555 #else
556     if ((rc = db->db_cnid->open(db->db_cnid, DBCNID, NULL, DB_HASH, open_flag, 0666 & ~mask)) != 0) {
557 #endif /* DB_VERSION_MAJOR >= 4 */
558         LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s",
559             db_strerror(rc));
560         db->db_didname->close(db->db_didname, 0);
561 #ifdef EXTENDED_DB
562         db->db_macname->close(db->db_macname, 0);
563         db->db_shortname->close(db->db_shortname, 0);
564         db->db_longname->close(db->db_longname, 0);
565 #endif /* EXTENDED_DB */
566         db->db_devino->close(db->db_devino, 0);
567         goto fail_appinit;
568     }
569
570 #ifdef FILE_MANGLING
571     /* filename mangling database.  Use a hash for this one. */
572     if ((rc = db_create(&db->db_mangle, db->dbenv, 0)) != 0) {
573         LOG(log_error, logtype_default, "cnid_open: Failed to create mangle database: %s", db_strerror(rc));
574         db->db_didname->close(db->db_didname, 0);
575         db->db_devino->close(db->db_devino, 0);
576         db->db_cnid->close(db->db_cnid, 0);
577 #ifdef EXTENDED_DB
578         db->db_macname->close(db->db_macname, 0);
579         db->db_shortname->close(db->db_shortname, 0);
580         db->db_longname->close(db->db_longname, 0);
581 #endif /* EXTENDED_DB */
582         goto fail_appinit;
583     }
584
585 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
586     if ((rc = db->db_mangle->open(db->db_mangle, NULL, DBMANGLE, NULL, DB_HASH, open_flag | DB_AUTO_COMMIT, 0666 & ~mask)) != 0) {
587 #else
588     if ((rc = db->db_mangle->open(db->db_mangle, DBMANGLE, NULL, DB_HASH, open_flag, 0666 & ~mask)) != 0) {
589 #endif /* DB_VERSION_MAJOR >= 4 */
590         LOG(log_error, logtype_default, "cnid_open: Failed to open mangle database: %s", db_strerror(rc));
591         db->db_didname->close(db->db_didname, 0);
592         db->db_devino->close(db->db_devino, 0);
593         db->db_cnid->close(db->db_cnid, 0);
594 #ifdef EXTENDED_DB
595         db->db_macname->close(db->db_macname, 0);
596         db->db_shortname->close(db->db_shortname, 0);
597         db->db_longname->close(db->db_longname, 0);
598 #endif /* EXTENDED_DB */
599         goto fail_appinit;
600     }
601 #endif /* FILE_MANGLING */
602
603     /* Print out the version of BDB we're linked against. */
604     LOG(log_info, logtype_default, "CNID DB initialized using %s",
605         db_version(NULL, NULL, NULL));
606
607     return db;
608
609 fail_appinit:
610     LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment");
611     db->dbenv->close(db->dbenv, 0);
612
613 fail_lock:
614 #ifndef CNID_DB_CDB
615     if (db->lockfd > -1) {
616         close(db->lockfd);
617         (void)remove(db->lock_file);
618     }
619 #endif /* CNID_DB_CDB */
620
621 fail_adouble:
622
623 fail_db:
624     free(db);
625     return NULL;
626 }
627 #endif /* CNID_DB */
628
629