nsdbmgmt.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /*
  7. * Description (nsdbmgmt.h)
  8. *
  9. * The file describes the interface for managing information in
  10. * a Netscape (server) database. A database is composed of
  11. * two (libdbm) DB files. One of these (<dbname>.db) contains
  12. * records indexed by a string key. These records contain the
  13. * primary information in the database. A second DB file
  14. * (<dbname>.id) is used to map an integer id value to a string
  15. * key, which can then be used to locate a record in the first file.
  16. * The interface for retrieving information from a database is
  17. * described in nsdb.h.
  18. */
  19. #include <base/systems.h>
  20. #include <netsite.h>
  21. #include <base/file.h>
  22. #define __PRIVATE_NSDB
  23. #include <libaccess/nsdbmgmt.h>
  24. #include <base/util.h>
  25. /*
  26. * Description (ndbAllocId)
  27. *
  28. * This function allocates a unique id to be associated with a
  29. * name in the primary DB file. An id bitmap is maintained in
  30. * the primary DB file as a metadata record, and an entry is
  31. * created in the id-to-name DB for the assigned id and the
  32. * specified name. An allocated id value is always non-zero.
  33. *
  34. * Arguments:
  35. *
  36. * errp - error frame list pointer (may be null)
  37. * ndb - database handle from ndbOpen()
  38. * namelen - length of key of the desired record,
  39. * including null terminator if any
  40. * name - pointer to the key of the desired record
  41. * id - pointer to returned id value
  42. *
  43. * Returns:
  44. *
  45. * If successful, the return value is zero, and the allocated id
  46. * is returned through 'id'. Otherwise a non-zero error code is
  47. * returned (NDBERRxxxx - see nsdb.h). If an error list is
  48. * provided, an error frame will be generated when the return
  49. * value is non-zero.
  50. */
  51. int ndbAllocId(NSErr_t * errp,
  52. void * ndb, int namelen, char * name, unsigned int * id)
  53. {
  54. NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
  55. DBT key;
  56. DBT rec;
  57. unsigned char * idmap;
  58. unsigned char * newmap = 0;
  59. int m;
  60. int mmsk;
  61. uint32 idval;
  62. int myid;
  63. int i, n;
  64. int rv;
  65. long eid;
  66. /*
  67. * Ensure that the name does not start with the metadata
  68. * prefix character.
  69. */
  70. if (!name || (name[0] == NDB_MDPREFIX)) goto err_name;
  71. /*
  72. * Read the primary DB file metadata record containing the id
  73. * allocation bitmap.
  74. */
  75. /*
  76. * We need the primary and the id-to-name DB files open for write
  77. * (and implicitly read) access.
  78. */
  79. if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
  80. != (NDBF_WRNAME|NDBF_WRID)) {
  81. /* No, (re)open it */
  82. rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
  83. if (rv < 0) goto punt;
  84. }
  85. /* Set the key to the id allocation bitmap record name */
  86. key.data = (void *)NDB_IDMAP;
  87. key.size = strlen(NDB_IDMAP) + 1;
  88. rec.data = 0;
  89. rec.size = 0;
  90. /* Retrieve the record by its key */
  91. rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
  92. if (rv) goto err_mdget;
  93. /* Search for an available id in the bitmap */
  94. n = rec.size;
  95. idmap = (unsigned char *)rec.data;
  96. for (i = 0, m = 0; i < n; ++i) {
  97. m = idmap[i];
  98. if (m != 0) break;
  99. }
  100. /* Did we find a byte with an available bit? */
  101. if (m == 0) {
  102. /* No, need to grow the bitmap */
  103. newmap = (unsigned char *)MALLOC(rec.size + 32);
  104. if (newmap == 0) goto err_nomem1;
  105. /* Initialize free space at the beginning of the new map */
  106. for (i = 0; i < 32; ++i) {
  107. newmap[i] = 0xff;
  108. }
  109. /* Copy the old map after it */
  110. n += 32;
  111. for ( ; i < n; ++i) {
  112. newmap[i] = idmap[i-32];
  113. }
  114. /* Set i and m to allocate the new highest id value */
  115. i = 0;
  116. m = 0xff;
  117. }
  118. else {
  119. /*
  120. * It's unfortunate, but it appears to be necessary to copy the
  121. * the ?idmap record into a new buffer before updating it, rather
  122. * than simply updating it in place. The problem is that the
  123. * libdbm put routine deletes the old record and then re-inserts
  124. * it. But once it has deleted the old record, it may take the
  125. * opportunity to move another record into the space that the
  126. * old record occupied, which is the same space that the new
  127. * record occupies. So the new record data is overwritten before
  128. * new record is inserted. :-(
  129. */
  130. newmap = (unsigned char *)MALLOC(rec.size);
  131. if (newmap == 0) goto err_nomem2;
  132. memcpy((void *)newmap, (void *)idmap, rec.size);
  133. }
  134. /* Calculate the id associated with the low-order bit of byte i */
  135. myid = (n - i - 1) << 3;
  136. /* Find the first free (set) bit in that word */
  137. for (mmsk = 1; !(m & mmsk); mmsk <<= 1, myid += 1) ;
  138. /* Clear the bit */
  139. m &= ~mmsk;
  140. newmap[i] = m;
  141. /* Write the bitmap back out */
  142. rec.data = (void *)newmap;
  143. rec.size = n;
  144. rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
  145. /* Check for error on preceding put operation */
  146. if (rv) goto err_putpdb;
  147. /* Create the key for the id-to-name record */
  148. idval = myid;
  149. #if BYTE_ORDER == LITTLE_ENDIAN
  150. M_32_SWAP(idval);
  151. #endif
  152. key.data = (void *)&idval;
  153. key.size = sizeof(uint32);
  154. rec.data = (void *)name;
  155. rec.size = (namelen > 0) ? namelen : (strlen(name) + 1);
  156. /* Write the id-to-name record */
  157. rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
  158. if (rv) goto err_putidb;
  159. /* Return the id value + 1, to avoid returning a zero id */
  160. if (id) *id = myid + 1;
  161. punt:
  162. /* Free the new map space if any */
  163. if (newmap) {
  164. FREE(newmap);
  165. }
  166. return rv;
  167. err_name: /* invalid name parameter */
  168. eid = NSDBERR2000;
  169. rv = NDBERRNAME;
  170. if (name == 0) {
  171. name = "(null)";
  172. }
  173. else if ((namelen > 0) && (namelen != strlen(name) + 1)) {
  174. name = "(unprintable)";
  175. }
  176. (void)nserrGenerate(errp, rv, eid, NSDB_Program,
  177. 2,
  178. ndbp->ndb_pname, /* primary DB filename */
  179. name /* name string */
  180. );
  181. goto punt;
  182. err_mdget: /* error on get from primary DB file */
  183. eid = NSDBERR2020;
  184. rv = NDBERRMDGET;
  185. (void)nserrGenerate(errp, rv, eid, NSDB_Program,
  186. 2,
  187. ndbp->ndb_pname, /* primary DB filename */
  188. (char *)key.data /* key name string */
  189. );
  190. goto punt;
  191. err_nomem1:
  192. eid = NSDBERR2040;
  193. goto err_nomem;
  194. err_nomem2:
  195. eid = NSDBERR2060;
  196. err_nomem: /* insufficient memory */
  197. rv = NDBERRNOMEM;
  198. (void)nserrGenerate(errp, rv, eid, NSDB_Program, 0);
  199. goto punt;
  200. err_putpdb: /* error on put to primary DB file */
  201. eid = NSDBERR2080;
  202. rv = NDBERRMDPUT;
  203. (void)nserrGenerate(errp, rv, eid, NSDB_Program,
  204. 2,
  205. ndbp->ndb_pname, /* primary DB filename */
  206. (char *)key.data /* key name string */
  207. );
  208. goto punt;
  209. err_putidb: /* error on put to id-to-name DB */
  210. {
  211. char idstring[16];
  212. eid = NSDBERR2100;
  213. rv = NDBERRIDPUT;
  214. util_sprintf(idstring, "%d", myid);
  215. (void)nserrGenerate(errp, rv, eid, NSDB_Program,
  216. 2,
  217. ndbp->ndb_iname, /* id-to-name DB file */
  218. idstring /* id value for key */
  219. );
  220. }
  221. goto punt;
  222. }
  223. /*
  224. * Description (ndbDeleteName)
  225. *
  226. * This function deletes a named record from the primary DB file.
  227. *
  228. * Arguments:
  229. *
  230. * errp - error frame list pointer (may be null)
  231. * ndb - database handle from ndbOpen()
  232. * flags - (currently unused - should be zero)
  233. * namelen - length of name key, including null
  234. * terminator if any
  235. * name - pointer to name key
  236. *
  237. * Returns:
  238. *
  239. * If successful, the return value is zero. Otherwise a non-zero
  240. * error code is returned (NDBERRxxxx - see nsdberr.h). If an error
  241. * list is provided, an error frame will be generated when the
  242. * return value is non-zero.
  243. */
  244. int ndbDeleteName(NSErr_t * errp,
  245. void * ndb, int flags, int namelen, char * name)
  246. {
  247. NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
  248. DBT key;
  249. int eid;
  250. int rv;
  251. /* Is the primary DB open for write access? */
  252. if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
  253. /* No, (re)open it */
  254. rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
  255. if (rv) goto punt;
  256. }
  257. /* Set up the key descriptor */
  258. key.data = (void *)name;
  259. key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
  260. /* Delete the record from the primary DB file */
  261. rv = (*ndbp->ndb_pdb->del)(ndbp->ndb_pdb, &key, 0);
  262. if (rv) goto err_delpdb;
  263. /* Successful completion */
  264. return 0;
  265. /* Begin error handlers */
  266. err_delpdb: /* error deleting record from primary DB */
  267. eid = NSDBERR2200;
  268. rv = NDBERRNMDEL;
  269. (void)nserrGenerate(errp, rv, eid, NSDB_Program,
  270. 2,
  271. ndbp->ndb_pname, /* primary DB name */
  272. (char *)key.data /* primary key */
  273. );
  274. punt:
  275. return rv;
  276. }
  277. /*
  278. * Description (ndbFreeId)
  279. *
  280. * This function frees an id value associated with a name in the
  281. * primary DB file. It is normally called when the named record
  282. * is being deleted from the primary DB file. It deletes the
  283. * record in the id-to-name DB file that is keyed by the id value,
  284. * and updates the id allocation bitmap in the primary DB file.
  285. * The caller may specify the name that is associated with the id
  286. * value, in which case the id-to-name record will be fetched,
  287. * and the name matched, before the record is deleted. Alternatively
  288. * the name parameter can be specified as zero, and id-to-name
  289. * record will be deleted without a check.
  290. *
  291. * Arguments:
  292. *
  293. * errp - error frame list pointer (may be null)
  294. * ndb - database handle from ndbOpen()
  295. * namelen - length of name (including null terminator)
  296. * name - name associated with the id value (optional)
  297. * id - id value to be freed
  298. *
  299. * Returns:
  300. *
  301. * If successful, the return value is zero. Otherwise a non-zero
  302. * error code is returned, and an error frame is generated if the
  303. * caller provided an error frame list.
  304. */
  305. int ndbFreeId(NSErr_t * errp,
  306. void * ndb, int namelen, char * name, unsigned int id)
  307. {
  308. NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
  309. char * recname;
  310. DBT key;
  311. DBT rec;
  312. uint32 idval;
  313. int reclen;
  314. int mmsk;
  315. unsigned char * idmap = 0;
  316. int i;
  317. int eid;
  318. int rv;
  319. /*
  320. * We need the primary and the id-to-name DB files open for write
  321. * (and implicitly read) access.
  322. */
  323. if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
  324. != (NDBF_WRNAME|NDBF_WRID)) {
  325. /* No, (re)open it */
  326. rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
  327. if (rv) goto punt;
  328. }
  329. /* Was the name for this id value provided by the caller? */
  330. if (name) {
  331. /* Get length of name if not provided */
  332. if (namelen <= 0) namelen = strlen(name) + 1;
  333. /* Yes, look up the id and check for a match */
  334. rv = ndbIdToName(errp, ndb, id, &reclen, &recname);
  335. if (rv < 0) goto punt;
  336. /* Fail if the supplied name doesn't match */
  337. if ((namelen != reclen) ||
  338. strncmp(recname, name, reclen)) goto err_badid1;
  339. }
  340. /* Caller views the id space as starting at 1, but we start at 0 */
  341. id -= 1;
  342. /* Create the key for the id-to-name record */
  343. idval = id;
  344. #if BYTE_ORDER == LITTLE_ENDIAN
  345. M_32_SWAP(idval);
  346. #endif
  347. key.data = (void *)&idval;
  348. key.size = sizeof(uint32);
  349. /* Delete the id-to-name record */
  350. rv = (*ndbp->ndb_idb->del)(ndbp->ndb_idb, &key, 0);
  351. if (rv) goto err_del;
  352. /* Set the key to the id allocation bitmap record name */
  353. key.data = (void *)NDB_IDMAP;
  354. key.size = strlen(NDB_IDMAP) + 1;
  355. rec.data = 0;
  356. rec.size = 0;
  357. /* Retrieve the record by its key */
  358. rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
  359. if (rv) goto err_mdget;
  360. /* Make sure the id is in the range of the bitmap */
  361. i = (rec.size << 3) - id - 1;
  362. if (i < 0) goto err_badid2;
  363. /*
  364. * See comment in ndbAllocId() about updating ?idmap. Bottom line
  365. * is: we have to copy the record before updating it.
  366. */
  367. idmap = (unsigned char *)MALLOC(rec.size);
  368. if (idmap == 0) goto err_nomem;
  369. memcpy((void *)idmap, rec.data, rec.size);
  370. /* Calculate the index of the byte with this id's bit */
  371. i >>= 3;
  372. /* Calculate the bitmask for the bitmap byte */
  373. mmsk = 1 << (id & 7);
  374. /* Set the bit in the bitmap */
  375. idmap[i] |= mmsk;
  376. /* Write the bitmap back out */
  377. rec.data = (void *)idmap;
  378. rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
  379. if (rv) goto err_mdput;
  380. punt:
  381. if (idmap) {
  382. FREE(idmap);
  383. }
  384. return rv;
  385. err_badid1:
  386. /* Name associated with id doesn't match supplied name */
  387. eid = NSDBERR2300;
  388. rv = NDBERRBADID;
  389. goto err_id;
  390. err_del:
  391. /* Error deleting id-to-name record */
  392. eid = NSDBERR2320;
  393. rv = NDBERRIDDEL;
  394. goto err_dbio;
  395. err_mdget:
  396. /* Error reading id bitmap from primary DB file */
  397. eid = NSDBERR2340;
  398. rv = NDBERRMDGET;
  399. goto err_dbio;
  400. err_badid2:
  401. eid = NSDBERR2360;
  402. rv = NDBERRBADID;
  403. err_id:
  404. {
  405. char idbuf[16];
  406. util_sprintf(idbuf, "%d", id);
  407. nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, idbuf);
  408. }
  409. goto punt;
  410. err_nomem:
  411. eid = NSDBERR2380;
  412. rv = NDBERRNOMEM;
  413. nserrGenerate(errp, rv, eid, NSDB_Program, 0);
  414. goto punt;
  415. err_mdput:
  416. eid = NSDBERR2400;
  417. rv = NDBERRMDPUT;
  418. goto err_dbio;
  419. err_dbio:
  420. nserrGenerate(errp, rv, eid, NSDB_Program,
  421. 2, ndbp->ndb_pname, system_errmsg());
  422. goto punt;
  423. }
  424. /*
  425. * Description (ndbRenameId)
  426. *
  427. * This function changes the name associated with a specified id
  428. * int the id-to-name DB file.
  429. *
  430. * Arguments:
  431. *
  432. * errp - error frame list pointer (may be null)
  433. * ndb - database handle from ndbOpen()
  434. * namelen - length of new name string, including
  435. * null terminator if any
  436. * newname - pointer to the new name string
  437. * id - id value to be renamed
  438. *
  439. * Returns:
  440. *
  441. * The return value is zero if the operation is successful. An
  442. * error is indicated by a non-zero return value, and an error
  443. * frame is generated if the caller provided an error frame list.
  444. */
  445. int ndbRenameId(NSErr_t * errp,
  446. void * ndb, int namelen, char * newname, unsigned int id)
  447. {
  448. NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
  449. DBT key;
  450. DBT rec;
  451. uint32 idval = id - 1;
  452. int eid;
  453. int rv;
  454. /*
  455. * Ensure that the name does not start with the metadata
  456. * prefix character.
  457. */
  458. if (!newname || (newname[0] == NDB_MDPREFIX)) goto err_name;
  459. /*
  460. * We need the id-to-name DB file open for write
  461. * (and implicitly read) access.
  462. */
  463. if (!(ndbp->ndb_flags & NDBF_WRID)) {
  464. /* No, (re)open it */
  465. rv = ndbReOpen(errp, ndb, NDBF_WRID);
  466. if (rv) goto punt;
  467. }
  468. /* Set up record key */
  469. #if BYTE_ORDER == LITTLE_ENDIAN
  470. M_32_SWAP(idval);
  471. #endif
  472. key.data = (void *)&idval;
  473. key.size = sizeof(uint32);
  474. rec.data = 0;
  475. rec.size = 0;
  476. /* Retrieve the record by its key */
  477. rv = (*ndbp->ndb_idb->get)(ndbp->ndb_idb, &key, &rec, 0);
  478. if (rv) goto err_idget;
  479. /* Set up to write the new name */
  480. rec.data = (void *)newname;
  481. rec.size = (namelen > 0) ? namelen : (strlen(newname) + 1);
  482. /* Write the id-to-name record */
  483. rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
  484. if (rv) goto err_idput;
  485. punt:
  486. return rv;
  487. err_name:
  488. eid = NSDBERR2500;
  489. rv = NDBERRNAME;
  490. if (newname == 0) newname = "(null)";
  491. else if ((namelen > 0) && (namelen != (strlen(newname) + 1))) {
  492. newname = "(unprintable)";
  493. }
  494. (void)nserrGenerate(errp, rv, eid, NSDB_Program,
  495. 2,
  496. ndbp->ndb_pname, /* primary DB filename */
  497. newname /* name string */
  498. );
  499. goto punt;
  500. err_idget:
  501. /* Error getting id record from id-to-name database */
  502. eid = NSDBERR2520;
  503. rv = NDBERRGET;
  504. goto err_dbio;
  505. err_idput:
  506. /* Error putting id record back to id-to-name database */
  507. eid = NSDBERR2540;
  508. rv = NDBERRIDPUT;
  509. err_dbio:
  510. nserrGenerate(errp, rv, eid, NSDB_Program,
  511. 2, ndbp->ndb_pname, system_errmsg());
  512. goto punt;
  513. }
  514. /*
  515. * Description (ndbStoreName)
  516. *
  517. * This function stores a record, keyed by a specified name, in the
  518. * primary DB file. The record will overwrite any existing record
  519. * with the same key, unless NDBF_NEWNAME, is included in the 'flags'
  520. * argument. If NDBF_NEWNAME is set, and the record already exists,
  521. * it is not overwritten, and an error is returned.
  522. *
  523. * Arguments:
  524. *
  525. * errp - error frame list pointer (may be null)
  526. * ndb - database handle from ndbOpen()
  527. * flags - bit flags:
  528. * NDBF_NEWNAME - name is new
  529. * namelen - length of name key, including null
  530. * terminator if any
  531. * name - pointer to name key
  532. * reclen - length of the record data
  533. * recptr - pointer to the record data
  534. *
  535. * Returns:
  536. *
  537. * If successful, the return value is zero. Otherwise a non-zero
  538. * error code is returned, and an error frame is generated if the
  539. * caller provided an error frame list.
  540. */
  541. int ndbStoreName(NSErr_t * errp, void * ndb, int flags,
  542. int namelen, char * name, int reclen, char * recptr)
  543. {
  544. NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
  545. DBT key;
  546. DBT rec;
  547. int eid;
  548. int rv;
  549. /* Is the primary DB open for write access? */
  550. if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
  551. /* No, (re)open it */
  552. rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
  553. if (rv) goto punt;
  554. }
  555. /* Set up the key and record descriptors */
  556. key.data = (void *)name;
  557. key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
  558. rec.data = (void *)recptr;
  559. rec.size = reclen;
  560. /* Write the record to the primary DB file */
  561. rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec,
  562. (flags & NDBF_NEWNAME) ? R_NOOVERWRITE : 0);
  563. if (rv) goto err_put;
  564. punt:
  565. return rv;
  566. err_put:
  567. eid = NSDBERR2700;
  568. rv = NDBERRPUT;
  569. nserrGenerate(errp, rv, eid, NSDB_Program,
  570. 2, ndbp->ndb_pname, system_errmsg());
  571. goto punt;
  572. }