| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- /** BEGIN COPYRIGHT BLOCK
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- /*
- * Description (nsdbmgmt.h)
- *
- * The file describes the interface for managing information in
- * a Netscape (server) database. A 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.
- * The interface for retrieving information from a database is
- * described in nsdb.h.
- */
- #include <base/systems.h>
- #include <netsite.h>
- #include <base/file.h>
- #define __PRIVATE_NSDB
- #include <libaccess/nsdbmgmt.h>
- #include <base/util.h>
- /*
- * Description (ndbAllocId)
- *
- * This function allocates a unique id to be associated with a
- * name in the primary DB file. An id bitmap is maintained in
- * the primary DB file as a metadata record, and an entry is
- * created in the id-to-name DB for the assigned id and the
- * specified name. An allocated id value is always non-zero.
- *
- * Arguments:
- *
- * errp - error frame list pointer (may be null)
- * ndb - database handle from ndbOpen()
- * namelen - length of key of the desired record,
- * including null terminator if any
- * name - pointer to the key of the desired record
- * id - pointer to returned id value
- *
- * Returns:
- *
- * If successful, the return value is zero, and the allocated id
- * is returned through 'id'. 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 ndbAllocId(NSErr_t * errp,
- void * ndb, int namelen, char * name, unsigned int * id)
- {
- NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
- DBT key;
- DBT rec;
- unsigned char * idmap;
- unsigned char * newmap = 0;
- int m;
- int mmsk;
- uint32 idval;
- int myid;
- int i, n;
- int rv;
- long eid;
- /*
- * Ensure that the name does not start with the metadata
- * prefix character.
- */
- if (!name || (name[0] == NDB_MDPREFIX)) goto err_name;
- /*
- * Read the primary DB file metadata record containing the id
- * allocation bitmap.
- */
- /*
- * We need the primary and the id-to-name DB files open for write
- * (and implicitly read) access.
- */
- if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
- != (NDBF_WRNAME|NDBF_WRID)) {
- /* No, (re)open it */
- rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
- if (rv < 0) goto punt;
- }
- /* Set the key to the id allocation bitmap record name */
- key.data = (void *)NDB_IDMAP;
- key.size = strlen(NDB_IDMAP) + 1;
- 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_mdget;
- /* Search for an available id in the bitmap */
- n = rec.size;
- idmap = (unsigned char *)rec.data;
- for (i = 0, m = 0; i < n; ++i) {
- m = idmap[i];
- if (m != 0) break;
- }
- /* Did we find a byte with an available bit? */
- if (m == 0) {
- /* No, need to grow the bitmap */
- newmap = (unsigned char *)MALLOC(rec.size + 32);
- if (newmap == 0) goto err_nomem1;
- /* Initialize free space at the beginning of the new map */
- for (i = 0; i < 32; ++i) {
- newmap[i] = 0xff;
- }
- /* Copy the old map after it */
- n += 32;
- for ( ; i < n; ++i) {
- newmap[i] = idmap[i-32];
- }
- /* Set i and m to allocate the new highest id value */
- i = 0;
- m = 0xff;
- }
- else {
- /*
- * It's unfortunate, but it appears to be necessary to copy the
- * the ?idmap record into a new buffer before updating it, rather
- * than simply updating it in place. The problem is that the
- * libdbm put routine deletes the old record and then re-inserts
- * it. But once it has deleted the old record, it may take the
- * opportunity to move another record into the space that the
- * old record occupied, which is the same space that the new
- * record occupies. So the new record data is overwritten before
- * new record is inserted. :-(
- */
- newmap = (unsigned char *)MALLOC(rec.size);
- if (newmap == 0) goto err_nomem2;
- memcpy((void *)newmap, (void *)idmap, rec.size);
- }
- /* Calculate the id associated with the low-order bit of byte i */
- myid = (n - i - 1) << 3;
- /* Find the first free (set) bit in that word */
- for (mmsk = 1; !(m & mmsk); mmsk <<= 1, myid += 1) ;
- /* Clear the bit */
- m &= ~mmsk;
- newmap[i] = m;
- /* Write the bitmap back out */
- rec.data = (void *)newmap;
- rec.size = n;
- rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
- /* Check for error on preceding put operation */
- if (rv) goto err_putpdb;
- /* Create the key for the id-to-name record */
- idval = myid;
- #if BYTE_ORDER == LITTLE_ENDIAN
- M_32_SWAP(idval);
- #endif
- key.data = (void *)&idval;
- key.size = sizeof(uint32);
- rec.data = (void *)name;
- rec.size = (namelen > 0) ? namelen : (strlen(name) + 1);
- /* Write the id-to-name record */
- rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
- if (rv) goto err_putidb;
- /* Return the id value + 1, to avoid returning a zero id */
- if (id) *id = myid + 1;
- punt:
- /* Free the new map space if any */
- if (newmap) {
- FREE(newmap);
- }
- return rv;
- err_name: /* invalid name parameter */
- eid = NSDBERR2000;
- rv = NDBERRNAME;
- if (name == 0) {
- name = "(null)";
- }
- else if ((namelen > 0) && (namelen != strlen(name) + 1)) {
- name = "(unprintable)";
- }
- (void)nserrGenerate(errp, rv, eid, NSDB_Program,
- 2,
- ndbp->ndb_pname, /* primary DB filename */
- name /* name string */
- );
- goto punt;
- err_mdget: /* error on get from primary DB file */
- eid = NSDBERR2020;
- rv = NDBERRMDGET;
- (void)nserrGenerate(errp, rv, eid, NSDB_Program,
- 2,
- ndbp->ndb_pname, /* primary DB filename */
- (char *)key.data /* key name string */
- );
- goto punt;
- err_nomem1:
- eid = NSDBERR2040;
- goto err_nomem;
- err_nomem2:
- eid = NSDBERR2060;
- err_nomem: /* insufficient memory */
- rv = NDBERRNOMEM;
- (void)nserrGenerate(errp, rv, eid, NSDB_Program, 0);
- goto punt;
-
- err_putpdb: /* error on put to primary DB file */
- eid = NSDBERR2080;
- rv = NDBERRMDPUT;
- (void)nserrGenerate(errp, rv, eid, NSDB_Program,
- 2,
- ndbp->ndb_pname, /* primary DB filename */
- (char *)key.data /* key name string */
- );
- goto punt;
- err_putidb: /* error on put to id-to-name DB */
- {
- char idstring[16];
- eid = NSDBERR2100;
- rv = NDBERRIDPUT;
- util_sprintf(idstring, "%d", myid);
- (void)nserrGenerate(errp, rv, eid, NSDB_Program,
- 2,
- ndbp->ndb_iname, /* id-to-name DB file */
- idstring /* id value for key */
- );
- }
- goto punt;
- }
- /*
- * Description (ndbDeleteName)
- *
- * This function deletes a named record from the primary DB file.
- *
- * Arguments:
- *
- * errp - error frame list pointer (may be null)
- * ndb - database handle from ndbOpen()
- * flags - (currently unused - should be zero)
- * namelen - length of name key, including null
- * terminator if any
- * name - pointer to name key
- *
- * Returns:
- *
- * If successful, the return value is zero. Otherwise a non-zero
- * error code is returned (NDBERRxxxx - see nsdberr.h). If an error
- * list is provided, an error frame will be generated when the
- * return value is non-zero.
- */
- int ndbDeleteName(NSErr_t * errp,
- void * ndb, int flags, int namelen, char * name)
- {
- NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
- DBT key;
- int eid;
- int rv;
- /* Is the primary DB open for write access? */
- if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
- /* No, (re)open it */
- rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
- if (rv) goto punt;
- }
- /* Set up the key descriptor */
- key.data = (void *)name;
- key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
- /* Delete the record from the primary DB file */
- rv = (*ndbp->ndb_pdb->del)(ndbp->ndb_pdb, &key, 0);
- if (rv) goto err_delpdb;
- /* Successful completion */
- return 0;
- /* Begin error handlers */
- err_delpdb: /* error deleting record from primary DB */
- eid = NSDBERR2200;
- rv = NDBERRNMDEL;
- (void)nserrGenerate(errp, rv, eid, NSDB_Program,
- 2,
- ndbp->ndb_pname, /* primary DB name */
- (char *)key.data /* primary key */
- );
- punt:
- return rv;
- }
- /*
- * Description (ndbFreeId)
- *
- * This function frees an id value associated with a name in the
- * primary DB file. It is normally called when the named record
- * is being deleted from the primary DB file. It deletes the
- * record in the id-to-name DB file that is keyed by the id value,
- * and updates the id allocation bitmap in the primary DB file.
- * The caller may specify the name that is associated with the id
- * value, in which case the id-to-name record will be fetched,
- * and the name matched, before the record is deleted. Alternatively
- * the name parameter can be specified as zero, and id-to-name
- * record will be deleted without a check.
- *
- * Arguments:
- *
- * errp - error frame list pointer (may be null)
- * ndb - database handle from ndbOpen()
- * namelen - length of name (including null terminator)
- * name - name associated with the id value (optional)
- * id - id value to be freed
- *
- * Returns:
- *
- * If successful, the return value is zero. Otherwise a non-zero
- * error code is returned, and an error frame is generated if the
- * caller provided an error frame list.
- */
- int ndbFreeId(NSErr_t * errp,
- void * ndb, int namelen, char * name, unsigned int id)
- {
- NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
- char * recname;
- DBT key;
- DBT rec;
- uint32 idval;
- int reclen;
- int mmsk;
- unsigned char * idmap = 0;
- int i;
- int eid;
- int rv;
- /*
- * We need the primary and the id-to-name DB files open for write
- * (and implicitly read) access.
- */
- if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
- != (NDBF_WRNAME|NDBF_WRID)) {
- /* No, (re)open it */
- rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
- if (rv) goto punt;
- }
- /* Was the name for this id value provided by the caller? */
- if (name) {
- /* Get length of name if not provided */
- if (namelen <= 0) namelen = strlen(name) + 1;
- /* Yes, look up the id and check for a match */
- rv = ndbIdToName(errp, ndb, id, &reclen, &recname);
- if (rv < 0) goto punt;
- /* Fail if the supplied name doesn't match */
- if ((namelen != reclen) ||
- strncmp(recname, name, reclen)) goto err_badid1;
- }
- /* Caller views the id space as starting at 1, but we start at 0 */
- id -= 1;
- /* Create the key for the id-to-name record */
- idval = id;
- #if BYTE_ORDER == LITTLE_ENDIAN
- M_32_SWAP(idval);
- #endif
- key.data = (void *)&idval;
- key.size = sizeof(uint32);
- /* Delete the id-to-name record */
- rv = (*ndbp->ndb_idb->del)(ndbp->ndb_idb, &key, 0);
- if (rv) goto err_del;
- /* Set the key to the id allocation bitmap record name */
- key.data = (void *)NDB_IDMAP;
- key.size = strlen(NDB_IDMAP) + 1;
- 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_mdget;
- /* Make sure the id is in the range of the bitmap */
- i = (rec.size << 3) - id - 1;
- if (i < 0) goto err_badid2;
- /*
- * See comment in ndbAllocId() about updating ?idmap. Bottom line
- * is: we have to copy the record before updating it.
- */
- idmap = (unsigned char *)MALLOC(rec.size);
- if (idmap == 0) goto err_nomem;
- memcpy((void *)idmap, rec.data, rec.size);
- /* Calculate the index of the byte with this id's bit */
- i >>= 3;
- /* Calculate the bitmask for the bitmap byte */
- mmsk = 1 << (id & 7);
- /* Set the bit in the bitmap */
- idmap[i] |= mmsk;
- /* Write the bitmap back out */
- rec.data = (void *)idmap;
- rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
- if (rv) goto err_mdput;
- punt:
- if (idmap) {
- FREE(idmap);
- }
- return rv;
- err_badid1:
- /* Name associated with id doesn't match supplied name */
- eid = NSDBERR2300;
- rv = NDBERRBADID;
- goto err_id;
- err_del:
- /* Error deleting id-to-name record */
- eid = NSDBERR2320;
- rv = NDBERRIDDEL;
- goto err_dbio;
- err_mdget:
- /* Error reading id bitmap from primary DB file */
- eid = NSDBERR2340;
- rv = NDBERRMDGET;
- goto err_dbio;
- err_badid2:
- eid = NSDBERR2360;
- rv = NDBERRBADID;
- err_id:
- {
- char idbuf[16];
- util_sprintf(idbuf, "%d", id);
- nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, idbuf);
- }
- goto punt;
- err_nomem:
- eid = NSDBERR2380;
- rv = NDBERRNOMEM;
- nserrGenerate(errp, rv, eid, NSDB_Program, 0);
- goto punt;
- err_mdput:
- eid = NSDBERR2400;
- rv = NDBERRMDPUT;
- goto err_dbio;
- err_dbio:
- nserrGenerate(errp, rv, eid, NSDB_Program,
- 2, ndbp->ndb_pname, system_errmsg());
- goto punt;
- }
- /*
- * Description (ndbRenameId)
- *
- * This function changes the name associated with a specified id
- * int the id-to-name DB file.
- *
- * Arguments:
- *
- * errp - error frame list pointer (may be null)
- * ndb - database handle from ndbOpen()
- * namelen - length of new name string, including
- * null terminator if any
- * newname - pointer to the new name string
- * id - id value to be renamed
- *
- * Returns:
- *
- * The return value is zero if the operation is successful. An
- * error is indicated by a non-zero return value, and an error
- * frame is generated if the caller provided an error frame list.
- */
- int ndbRenameId(NSErr_t * errp,
- void * ndb, int namelen, char * newname, unsigned int id)
- {
- NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
- DBT key;
- DBT rec;
- uint32 idval = id - 1;
- int eid;
- int rv;
- /*
- * Ensure that the name does not start with the metadata
- * prefix character.
- */
- if (!newname || (newname[0] == NDB_MDPREFIX)) goto err_name;
- /*
- * We need the id-to-name DB file open for write
- * (and implicitly read) access.
- */
- if (!(ndbp->ndb_flags & NDBF_WRID)) {
- /* No, (re)open it */
- rv = ndbReOpen(errp, ndb, NDBF_WRID);
- if (rv) goto punt;
- }
- /* Set up record key */
- #if BYTE_ORDER == LITTLE_ENDIAN
- M_32_SWAP(idval);
- #endif
- key.data = (void *)&idval;
- key.size = sizeof(uint32);
- 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_idget;
- /* Set up to write the new name */
- rec.data = (void *)newname;
- rec.size = (namelen > 0) ? namelen : (strlen(newname) + 1);
- /* Write the id-to-name record */
- rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
- if (rv) goto err_idput;
- punt:
- return rv;
- err_name:
- eid = NSDBERR2500;
- rv = NDBERRNAME;
- if (newname == 0) newname = "(null)";
- else if ((namelen > 0) && (namelen != (strlen(newname) + 1))) {
- newname = "(unprintable)";
- }
- (void)nserrGenerate(errp, rv, eid, NSDB_Program,
- 2,
- ndbp->ndb_pname, /* primary DB filename */
- newname /* name string */
- );
- goto punt;
- err_idget:
- /* Error getting id record from id-to-name database */
- eid = NSDBERR2520;
- rv = NDBERRGET;
- goto err_dbio;
- err_idput:
- /* Error putting id record back to id-to-name database */
- eid = NSDBERR2540;
- rv = NDBERRIDPUT;
- err_dbio:
- nserrGenerate(errp, rv, eid, NSDB_Program,
- 2, ndbp->ndb_pname, system_errmsg());
- goto punt;
- }
- /*
- * Description (ndbStoreName)
- *
- * This function stores a record, keyed by a specified name, in the
- * primary DB file. The record will overwrite any existing record
- * with the same key, unless NDBF_NEWNAME, is included in the 'flags'
- * argument. If NDBF_NEWNAME is set, and the record already exists,
- * it is not overwritten, and an error is returned.
- *
- * Arguments:
- *
- * errp - error frame list pointer (may be null)
- * ndb - database handle from ndbOpen()
- * flags - bit flags:
- * NDBF_NEWNAME - name is new
- * namelen - length of name key, including null
- * terminator if any
- * name - pointer to name key
- * reclen - length of the record data
- * recptr - pointer to the record data
- *
- * Returns:
- *
- * If successful, the return value is zero. Otherwise a non-zero
- * error code is returned, and an error frame is generated if the
- * caller provided an error frame list.
- */
- int ndbStoreName(NSErr_t * errp, void * ndb, int flags,
- int namelen, char * name, int reclen, char * recptr)
- {
- NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
- DBT key;
- DBT rec;
- int eid;
- int rv;
- /* Is the primary DB open for write access? */
- if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
- /* No, (re)open it */
- rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
- if (rv) goto punt;
- }
- /* Set up the key and record descriptors */
- key.data = (void *)name;
- key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
- rec.data = (void *)recptr;
- rec.size = reclen;
- /* Write the record to the primary DB file */
- rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec,
- (flags & NDBF_NEWNAME) ? R_NOOVERWRITE : 0);
- if (rv) goto err_put;
- punt:
- return rv;
- err_put:
- eid = NSDBERR2700;
- rv = NDBERRPUT;
- nserrGenerate(errp, rv, eid, NSDB_Program,
- 2, ndbp->ndb_pname, system_errmsg());
- goto punt;
- }
|