summaryrefslogtreecommitdiffstats
path: root/lib/libaccess/nsdb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libaccess/nsdb.cpp')
-rw-r--r--lib/libaccess/nsdb.cpp836
1 files changed, 836 insertions, 0 deletions
diff --git a/lib/libaccess/nsdb.cpp b/lib/libaccess/nsdb.cpp
new file mode 100644
index 00000000..0479b8f3
--- /dev/null
+++ b/lib/libaccess/nsdb.cpp
@@ -0,0 +1,836 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsdb.c)
+ *
+ * This provides access to a Netscape server database.
+ * A server database is composed of two (libdbm) DB files. One
+ * of these (<dbname>.db) contains records indexed by a string
+ * key. These records contain the primary information in the
+ * database. A second DB file (<dbname>.id) is used to map an
+ * integer id value to a string key, which can then be used to
+ * locate a record in the first file.
+ *
+ * Normally the records in the primary DB file will contain the
+ * id values which are used to key the id-to-name DB. When this
+ * is the case, it is possible to construct the id-to-name DB from
+ * the primary DB file, and an interface is provided to facilitate
+ * this.
+ */
+
+#include <stdio.h>
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#define __PRIVATE_NSDB
+#include <libaccess/nsdb.h>
+
+#include <errno.h>
+
+#define NDBMODE 0644 /* mode for creating files */
+
+char * NSDB_Program = "NSDB"; /* NSDB facility name */
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (ndbClose)
+ *
+ * This function closes the specified database. This involves
+ * closing the primary and id-to-name DB files, and freeing the
+ * NSDB_t object.
+ *
+ * Arguments:
+ *
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ *
+ */
+
+void ndbClose(void * ndb, int flags)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+
+ if (ndbp->ndb_flags & (NDBF_WRNAME|NDBF_RDNAME)) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ }
+
+ if (ndbp->ndb_flags & (NDBF_WRID|NDBF_RDID)) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+
+ if (ndbp->ndb_pname) {
+ FREE(ndbp->ndb_pname);
+ }
+
+ if (ndbp->ndb_iname) {
+ FREE(ndbp->ndb_iname);
+ }
+
+ FREE(ndbp);
+}
+
+/*
+ * Description (ndbEnumerate)
+ *
+ * This function is called to enumerate the records of the primary
+ * DB file to a caller-specified function. The function specified
+ * by the caller is called with the name (key), length and address
+ * of each record in the primary DB file. The 'flags' argument can
+ * be used to select normal data records, metadata records, or both.
+ * If the 'flags' value is zero, only normal data records are
+ * enumerated. The function specified by the caller returns -1 to
+ * terminate the enumeration, 0 to continue it, or +1 to restart
+ * the enumeration from the beginning.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - bit flags:
+ * NDBF_ENUMNORM - normal data records
+ * NDBF_ENUMMETA - metadata records
+ * func - pointer to caller's enumeration function
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if an
+ * error frame list was provided by the caller.
+ */
+
+int ndbEnumerate(NSErr_t * errp, void * ndb, int flags, void * argp,
+#ifdef UnixWare
+ ArgFn_ndbEnum func) /* for ANSI C++ standard, see nsdb.h */
+#else
+ int (*func)(NSErr_t * ferrp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr))
+#endif
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int rv;
+ int dbflag;
+
+ /* Is the user DB open for reading names? */
+ if (!(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDNAME);
+ if (rv) goto punt;
+ }
+
+ if (flags == 0) flags = NDBF_ENUMNORM;
+
+ for (dbflag = R_FIRST; ; dbflag = (rv > 0) ? R_FIRST : R_NEXT) {
+
+ /* Retrieve the next (first) record from the primary DB */
+ rv = (*ndbp->ndb_pdb->seq)(ndbp->ndb_pdb, &key, &rec, dbflag);
+ if (rv) break;
+
+ /* Is this a metadata record? */
+ if (*(char *)key.data == NDB_MDPREFIX) {
+
+ /* Yes, skip it if metadata was not requested */
+ if (!(flags & NDBF_ENUMMETA)) continue;
+ }
+ else {
+ /* Skip normal data if not requested */
+ if (!(flags & NDBF_ENUMNORM)) continue;
+ }
+
+ /* Pass this record to the caller's function */
+ rv = (*func)(errp, argp,
+ key.size, (char *)key.data, rec.size, (char *)rec.data);
+ if (rv < 0) break;
+ }
+
+ /* Indicate success */
+ rv = 0;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (ndbFindName)
+ *
+ * This function retrieves from the database a record with the
+ * specified key.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of the key, including null
+ * terminator if any
+ * name - pointer to the key of the desired record
+ * reclen - pointer to returned record length
+ * recptr - pointer to returned record pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero, and the length and
+ * address of the returned record are returned through reclen and
+ * recptr. Otherwise the return value is non-zero, and an error
+ * frame is generated if an error frame list was provided by the
+ * caller.
+ *
+ * Notes:
+ *
+ * The record buffer is dynamically allocated and is freed
+ * automatically when the database is closed.
+ */
+
+int ndbFindName(NSErr_t * errp, void * ndb, int namelen, char * name,
+ int * reclen, char **recptr)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Is the user DB open for reading names? */
+ if (!(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDNAME);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key. Include the terminating null byte. */
+ key.data = (void *)name;
+ key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ /* Initialize record buffer descriptor */
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_pget;
+
+ /* Return record length and address */
+ if (reclen) *reclen = rec.size;
+ if (recptr) *recptr = (char *)rec.data;
+
+ /* Indicate success */
+ rv = 0;
+
+ punt:
+ return rv;
+
+ err_pget:
+ eid = NSDBERR1000;
+ rv = NDBERRGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, name);
+ goto punt;
+}
+
+/*
+ * Description (ndbIdToName)
+ *
+ * This function looks up a specified id in the id-to-name DB
+ * file, and returns the associated name string. This name
+ * can be used to retrieve a record using ndbFindName().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * id - id to look up
+ * plen - pointer to returned length of name
+ * (may be null, length includes null terminator
+ * in a string)
+ * pname - pointer to returned name string pointer
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful. An
+ * error is indicated by a negative return value (see nsdberr.h),
+ * and an error frame is generated if an error frame list was
+ * provided by the caller.
+ */
+
+int ndbIdToName(NSErr_t * errp,
+ void * ndb, unsigned int id, int * plen, char **pname)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ char * name = 0;
+ int namelen = 0;
+ uint32 myid = id - 1;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Is the id-to-name DB open for reading ids? */
+ if (!(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDID);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(myid);
+#endif
+ key.data = (void *)&myid;
+ key.size = sizeof(myid);
+
+ /* Initialize record buffer descriptor */
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_idb->get)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_iget;
+
+ /* Get the name pointer (terminating null is part of the name) */
+ namelen = rec.size;
+ name = (char *) rec.data;
+
+ punt:
+ /* Return name length and size if requested */
+ if (plen) *plen = namelen;
+ if (pname) *pname = name;
+
+ return rv;
+
+ err_iget:
+ eid = NSDBERR1100;
+ rv = NDBERRGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_iname, system_errmsg());
+ goto punt;
+}
+
+/*
+ * Description (ndbInitPrimary)
+ *
+ * This function creates and initializes the primary DB file.
+ * Initialization involves writing any required metadata records.
+ * Currently there is a ?dbtype record, which specifies the nsdb
+ * version number, and a database type and version number that
+ * were passed as arguments to ndbOpen(). There is also a
+ * ?idmap record, which contains an allocation bitmap for id values
+ * used as keys in the associated id-to-name DB file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if an
+ * error frame list was provided by the caller.
+ */
+
+int ndbInitPrimary(NSErr_t * errp, void * ndb)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32 m;
+ int i;
+#endif
+ int eid; /* error id code */
+ int rv; /* result value */
+ uint32 dbtype[4];
+
+ /* Error if the primary DB is marked as existing already */
+ if (!(ndbp->ndb_flags & NDBF_NONAME)) goto err_exists;
+
+ /* First create the primary DB file */
+ ndbp->ndb_pdb = dbopen(ndbp->ndb_pname, O_RDWR | O_CREAT | O_TRUNC,
+ NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open;
+
+ /* Generate data for the ?dbtype record */
+ dbtype[0] = NDB_VERSION;
+ dbtype[1] = ndbp->ndb_dbtype;
+ dbtype[2] = ndbp->ndb_version;
+ dbtype[3] = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ for (i = 0; i < 4; ++i) {
+ m = dbtype[i];
+ M_32_SWAP(m);
+ dbtype[i] = m;
+ }
+#endif
+
+ /* Set up descriptors for the ?dbtype record key and data */
+ key.data = (void *)NDB_DBTYPE;
+ key.size = strlen(NDB_DBTYPE) + 1;
+
+ rec.data = (void *)dbtype;
+ rec.size = sizeof(dbtype);
+
+ /* Write the ?dbtype record out */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mput1;
+
+ /* Write out an empty ?idmap record */
+ key.data = (void *)NDB_IDMAP;
+ key.size = strlen(NDB_IDMAP) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Write the ?idmap record */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mput2;
+
+ /* Close the DB file */
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+
+ /* Clear the flag that says the primary DB file does not exist */
+ ndbp->ndb_flags &= ~(NDBF_NONAME|NDBF_RDNAME|NDBF_WRNAME);
+
+ /* Indicate success */
+ return 0;
+
+ err_exists:
+ /* Primary database already exists */
+ eid = NSDBERR1200;
+ rv = NDBERREXIST;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 1, ndbp->ndb_pname);
+ return rv;
+
+ err_open:
+ /* Error opening primary database for write */
+ eid = NSDBERR1220;
+ rv = NDBERROPEN;
+ goto err_dbio;
+
+ err_mput1:
+ /* Error writing "?dbtype" record */
+ eid = NSDBERR1240;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_mput2:
+ /* Error writing "?idmap" record */
+ eid = NSDBERR1260;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_dbio:
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+
+ /* Close the primary DB file if it exists */
+ if (ndbp->ndb_pdb) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~(NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Delete the file */
+ system_unlink(ndbp->ndb_pname);
+ return rv;
+}
+
+/*
+ * Description (ndbOpen)
+ *
+ * This function opens a server database by name. The specified
+ * name may be the name of the primary DB file, or the name
+ * without the ".db" suffix. This function will attempt to open
+ * both the primary and the id-to-name DB files for read access.
+ * If either of the DB files do not exist, they are not created
+ * here, but a handle for the database will still be returned.
+ * The DB files will be created when a subsequent access writes
+ * to the database. The caller also specifies an application
+ * database type, which is checked against a value stored in
+ * in the database metadata, if the primary DB file exists, or
+ * which is stored in the file metadata when the file is created.
+ * A type-specific version number is passed and returned. The
+ * value passed will be stored in the file metadata if it is
+ * subsequently created. If the file exists, the value in the
+ * file metadata is returned, and it is the caller's responsibility
+ * to interpret it.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * dbname - primary DB filename
+ * flags - (currently unused - should be zero)
+ * dbtype - application DB type (NDB_TYPE_xxxxx)
+ * version - (in/out) type-specific version number
+ *
+ * Returns:
+ *
+ * A handle that can be used for subsequent accesses to the database
+ * is returned, or 0, if an error occurs, and an error frame is
+ * generated if an error frame list was provided by the caller.
+ */
+
+void * ndbOpen(NSErr_t * errp,
+ char * dbname, int flags, int dbtype, int * version)
+{
+ NSDB_t * ndbp = 0; /* database object pointer */
+ char * pname = 0; /* primary DB file name */
+ char * iname = 0; /* id-to-name DB file name */
+ int namelen;
+ uint32 dbtrec[4];
+ uint32 m;
+ DBT key;
+ DBT rec;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Get the database name */
+ namelen = strlen(dbname);
+ if (!strcmp(&dbname[namelen-3], ".db")) {
+ namelen -= 3;
+ }
+
+ /* Get the primary DB file name */
+ pname = (char *)MALLOC(namelen + 4);
+ if (pname == 0) goto err_nomem1;
+ strncpy(pname, dbname, namelen);
+ strcpy(&pname[namelen], ".db");
+
+ /* Get the id-to-name DB file name */
+ iname = (char *)MALLOC(namelen + 4);
+ if (iname == 0) goto err_nomem2;
+ strncpy(iname, dbname, namelen);
+ strcpy(&iname[namelen], ".id");
+
+ /* Allocate the database object */
+ ndbp = (NSDB_t *)MALLOC(sizeof(NSDB_t));
+ if (ndbp == 0) goto err_nomem3;
+
+ /* Initialize the database object */
+ ndbp->ndb_pname = pname;
+ ndbp->ndb_pdb = 0;
+ ndbp->ndb_iname = iname;
+ ndbp->ndb_idb = 0;
+ ndbp->ndb_flags = 0;
+ ndbp->ndb_dbtype = dbtype;
+ ndbp->ndb_version = (version) ? *version : 0;
+
+ /* Open the primary DB file */
+ ndbp->ndb_pdb = dbopen(pname, O_RDONLY, NDBMODE, DB_HASH, 0);
+
+ /* Was it there? */
+ if (ndbp->ndb_pdb) {
+
+ /* Retrieve the ?dbtype record */
+ key.data = (void *)NDB_DBTYPE;
+ key.size = strlen(NDB_DBTYPE) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Read the ?dbtype record */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdget;
+
+ /* Check it out */
+ if (rec.size < 16) goto err_fmt;
+
+ /* Copy data to an aligned area */
+ memcpy((void *)dbtrec, rec.data, sizeof(dbtrec));
+
+ /* Get the NSDB version number */
+ m = dbtrec[0];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* Assume forward compatibility with versions up to current + 0.5 */
+ if (m > (NDB_VERSION + 5)) goto err_vers;
+
+ /* XXX Assume infinite backward compatibility */
+
+ /* Get the application database type */
+ m = dbtrec[1];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* It's got to match */
+ if (m != dbtype) goto err_type;
+
+ /* Get the type-specific version number */
+ m = dbtrec[3];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* Don't check it. Just return it. */
+ if (version) *version = m;
+
+ /* The value in dbtrec[3] is currently ignored */
+
+ /* Mark the primary DB file open for read access */
+ ndbp->ndb_flags |= NDBF_RDNAME;
+ }
+ else {
+ /* Indicate that the primary DB file does not exist */
+ ndbp->ndb_flags |= NDBF_NONAME;
+ }
+
+ return (void *)ndbp;
+
+ err_nomem1:
+ eid = NSDBERR1400;
+ rv = NDBERRNOMEM;
+ goto err_nomem;
+
+ err_nomem2:
+ eid = NSDBERR1420;
+ rv = NDBERRNOMEM;
+ goto err_nomem;
+
+ err_nomem3:
+ eid = NSDBERR1440;
+ rv = NDBERRNOMEM;
+ err_nomem:
+ nserrGenerate(errp, rv, eid, NSDB_Program, 0);
+ goto punt;
+
+ err_mdget:
+ eid = NSDBERR1460;
+ rv = NDBERRMDGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname,
+ system_errmsg());
+ goto err_ret;
+
+ err_fmt:
+ eid = NSDBERR1480;
+ rv = NDBERRMDFMT;
+ goto err_ret;
+
+ err_vers:
+ {
+ char vnbuf[16];
+
+ eid = NSDBERR1500;
+ rv = NDBERRVERS;
+ sprintf(vnbuf, "%d", (int)m);
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, vnbuf);
+ }
+ goto punt;
+
+ err_type:
+ eid = NSDBERR1520;
+ rv = NDBERRDBTYPE;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSDB_Program, 1, ndbp->ndb_pname);
+ goto punt;
+
+ punt:
+ /* Error clean-up */
+ if (pname) FREE(pname);
+ if (iname) FREE(iname);
+ if (ndbp) {
+ /* Close the DB files if we got as far as opening them */
+ if (ndbp->ndb_pdb) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ }
+ if (ndbp->ndb_idb) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+ FREE(ndbp);
+ }
+ return 0;
+}
+
+/*
+ * Description (ndbReOpen)
+ *
+ * This function is called to ensure that the primary DB file
+ * and/or the id-to-name DB file are open with specified access
+ * rights. For example, a file may be open for read, and it needs
+ * to be open for write. Both the primary and id-to-name DB files
+ * can be manipulated with a single call.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned (NDBERRxxxx - see nsdb.h). If an error
+ * list is provided, an error frame will be generated when the
+ * return value is non-zero.
+ */
+
+int ndbReOpen(NSErr_t * errp, void * ndb, int flags)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ char * dbname; /* database name pointer */
+ int eid;
+ int rv;
+
+ /* Want to read or write the primary DB file? */
+ if (flags & (NDBF_RDNAME|NDBF_WRNAME)) {
+
+ /* Need to open for write? */
+ if ((flags & NDBF_WRNAME) && !(ndbp->ndb_flags & NDBF_WRNAME)) {
+
+ /* If it's already open for read, close it first */
+ if (ndbp->ndb_flags & NDBF_RDNAME) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~NDBF_RDNAME;
+ }
+
+ /* Create it if it doesn't exist */
+ if (ndbp->ndb_flags & NDBF_NONAME) {
+ rv = ndbInitPrimary(errp, ndb);
+ if (rv) goto err_init;
+ }
+
+ /* Open primary DB file for write access */
+ dbname = ndbp->ndb_pname;
+ ndbp->ndb_pdb = dbopen(dbname, O_RDWR, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open1;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= (NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Need to open for read? */
+ if ((flags & NDBF_RDNAME) && !(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* If it's already open for write, close it first */
+ if (ndbp->ndb_flags & NDBF_WRNAME) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~(NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Open primary DB file for read access */
+ dbname = ndbp->ndb_pname;
+ ndbp->ndb_pdb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open2;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= NDBF_RDNAME;
+ }
+ }
+
+ /* Want to read or write the id-to-name DB file? */
+ if (flags & (NDBF_RDID|NDBF_WRID)) {
+
+ /* Need to open for write? */
+ if ((flags & NDBF_WRID) && !(ndbp->ndb_flags & NDBF_WRID)) {
+
+ /*
+ * If it's not open for read yet, try to open it for read
+ * in order to find out if it exists.
+ */
+ if (!(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* Open id-to-name DB file for read access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH,0);
+
+ /* Does it exist? */
+ if (ndbp->ndb_idb == 0) {
+
+ /* No, create it */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname,O_RDWR | O_CREAT | O_TRUNC,
+ NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open3;
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+ else {
+ /* Mark it open for read */
+ ndbp->ndb_flags |= NDBF_RDID;
+ }
+ }
+
+ /* If it's already open for read, close it first */
+ if (ndbp->ndb_flags & NDBF_RDID) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ ndbp->ndb_flags &= ~NDBF_RDID;
+ }
+
+ /* Open id-to-name DB file for write access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDWR, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open4;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= (NDBF_RDID|NDBF_WRID);
+ }
+
+ /* Need to open for read? */
+ if ((flags & NDBF_RDID) && !(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* If it's already open for write, close it first */
+ if (ndbp->ndb_flags & NDBF_WRID) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ ndbp->ndb_flags &= ~(NDBF_RDID|NDBF_WRID);
+ }
+
+ /* Open id-to-name DB file for read access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open5;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= NDBF_RDID;
+ }
+ }
+
+ /* Successful completion */
+ return 0;
+
+ /* Begin error handlers */
+
+ err_init: /* failed to create primary DB file */
+ (void)nserrGenerate(errp, NDBERRPINIT, NSDBERR1600, NSDB_Program,
+ 1,
+ ndbp->ndb_pname /* primary DB filename */
+ );
+ rv = NDBERRPINIT;
+ goto punt;
+
+ err_open1:
+ eid = NSDBERR1620;
+ goto err_open;
+
+ err_open2:
+ eid = NSDBERR1640;
+ goto err_open;
+
+ err_open3:
+ eid = NSDBERR1660;
+ goto err_open;
+
+ err_open4:
+ eid = NSDBERR1680;
+ goto err_open;
+
+ err_open5:
+ eid = NSDBERR1700;
+ goto err_open;
+
+ err_open: /* database open error */
+ rv = NDBERROPEN;
+ (void)nserrGenerate(errp, NDBERROPEN, eid, NSDB_Program,
+ 2, dbname, system_errmsg());
+
+ punt:
+ return rv;
+}
+
+NSPR_END_EXTERN_C
+