2
0

apr_dbm_berkeleydb.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
  2. * applicable.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "apr_strings.h"
  17. #define APR_WANT_MEMFUNC
  18. #include "apr_want.h"
  19. #define APU_WANT_DB
  20. #include "apu_want.h"
  21. #if APR_HAVE_STDLIB_H
  22. #include <stdlib.h> /* for abort() */
  23. #endif
  24. #include "apu.h"
  25. #if APU_HAVE_DB
  26. #include "apr_dbm_private.h"
  27. /*
  28. * We pick up all varieties of Berkeley DB through db.h (included through
  29. * apu_select_dbm.h). This code has been compiled/tested against DB1,
  30. * DB_185, DB2, DB3, and DB4.
  31. */
  32. #if defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 4)
  33. /* We will treat anything greater than 4.1 as DB4.
  34. * We can treat 4.0 as DB3.
  35. */
  36. #if defined(DB_VERSION_MINOR) && (DB_VERSION_MINOR >= 1)
  37. #define DB_VER 4
  38. #else
  39. #define DB_VER 3
  40. #endif
  41. #elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 3)
  42. #define DB_VER 3
  43. #elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2)
  44. #define DB_VER 2
  45. #else
  46. #define DB_VER 1
  47. #endif
  48. typedef struct {
  49. DB *bdb;
  50. #if DB_VER != 1
  51. DBC *curs;
  52. #endif
  53. } real_file_t;
  54. #if DB_VER == 1
  55. #define TXN_ARG
  56. #else
  57. #define TXN_ARG NULL,
  58. #endif
  59. #define GET_BDB(f) (((real_file_t *)(f))->bdb)
  60. #define do_fetch(bdb, k, v) ((*(bdb)->get)(bdb, TXN_ARG &(k), &(v), 0))
  61. #if DB_VER == 1
  62. #include <sys/fcntl.h>
  63. #define APR_DBM_DBMODE_RO O_RDONLY
  64. #define APR_DBM_DBMODE_RW O_RDWR
  65. #define APR_DBM_DBMODE_RWCREATE (O_CREAT | O_RDWR)
  66. #define APR_DBM_DBMODE_RWTRUNC (O_CREAT | O_RDWR | O_TRUNC)
  67. #else
  68. #define APR_DBM_DBMODE_RO DB_RDONLY
  69. #define APR_DBM_DBMODE_RW 0
  70. #define APR_DBM_DBMODE_RWCREATE DB_CREATE
  71. #define APR_DBM_DBMODE_RWTRUNC DB_TRUNCATE
  72. #endif /* DBVER == 1 */
  73. /* --------------------------------------------------------------------------
  74. **
  75. ** UTILITY FUNCTIONS
  76. */
  77. /* map a DB error to an apr_status_t */
  78. static apr_status_t db2s(int dberr)
  79. {
  80. if (dberr != 0) {
  81. /* ### need to fix this */
  82. return APR_OS_START_USEERR + dberr;
  83. }
  84. return APR_SUCCESS;
  85. }
  86. static apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said)
  87. {
  88. apr_status_t rv = APR_SUCCESS;
  89. /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */
  90. if (dbm_said == APR_SUCCESS) {
  91. dbm->errcode = 0;
  92. dbm->errmsg = NULL;
  93. }
  94. else {
  95. /* ### need to fix. dberr was tossed in db2s(). */
  96. /* ### use db_strerror() */
  97. dbm->errcode = dbm_said;
  98. #if DB_VER == 1 || DB_VER == 2
  99. dbm->errmsg = NULL;
  100. #else
  101. dbm->errmsg = db_strerror(dbm_said - APR_OS_START_USEERR);
  102. #endif
  103. rv = dbm_said;
  104. }
  105. return rv;
  106. }
  107. /* --------------------------------------------------------------------------
  108. **
  109. ** DEFINE THE VTABLE FUNCTIONS FOR BERKELEY DB
  110. **
  111. ** ### we may need three sets of these: db1, db2, db3
  112. */
  113. static apr_status_t vt_db_open(apr_dbm_t **pdb, const char *pathname,
  114. apr_int32_t mode, apr_fileperms_t perm,
  115. apr_pool_t *pool)
  116. {
  117. real_file_t file;
  118. int dbmode;
  119. *pdb = NULL;
  120. switch (mode) {
  121. case APR_DBM_READONLY:
  122. dbmode = APR_DBM_DBMODE_RO;
  123. break;
  124. case APR_DBM_READWRITE:
  125. dbmode = APR_DBM_DBMODE_RW;
  126. break;
  127. case APR_DBM_RWCREATE:
  128. dbmode = APR_DBM_DBMODE_RWCREATE;
  129. break;
  130. case APR_DBM_RWTRUNC:
  131. dbmode = APR_DBM_DBMODE_RWTRUNC;
  132. break;
  133. default:
  134. return APR_EINVAL;
  135. }
  136. {
  137. int dberr;
  138. #if DB_VER >= 3
  139. if ((dberr = db_create(&file.bdb, NULL, 0)) == 0) {
  140. if ((dberr = (*file.bdb->open)(file.bdb,
  141. #if DB_VER == 4
  142. NULL,
  143. #endif
  144. pathname, NULL,
  145. DB_HASH, dbmode,
  146. apr_posix_perms2mode(perm))) != 0) {
  147. /* close the DB handler */
  148. (void) (*file.bdb->close)(file.bdb, 0);
  149. }
  150. }
  151. file.curs = NULL;
  152. #elif DB_VER == 2
  153. dberr = db_open(pathname, DB_HASH, dbmode, apr_posix_perms2mode(perm),
  154. NULL, NULL, &file.bdb);
  155. file.curs = NULL;
  156. #else
  157. file.bdb = dbopen(pathname, dbmode, apr_posix_perms2mode(perm),
  158. DB_HASH, NULL);
  159. if (file.bdb == NULL)
  160. return APR_EGENERAL; /* ### need a better error */
  161. dberr = 0;
  162. #endif
  163. if (dberr != 0)
  164. return db2s(dberr);
  165. }
  166. /* we have an open database... return it */
  167. *pdb = apr_pcalloc(pool, sizeof(**pdb));
  168. (*pdb)->pool = pool;
  169. (*pdb)->type = &apr_dbm_type_db;
  170. (*pdb)->file = apr_pmemdup(pool, &file, sizeof(file));
  171. /* ### register a cleanup to close the DBM? */
  172. return APR_SUCCESS;
  173. }
  174. static void vt_db_close(apr_dbm_t *dbm)
  175. {
  176. (*GET_BDB(dbm->file)->close)(GET_BDB(dbm->file)
  177. #if DB_VER != 1
  178. , 0
  179. #endif
  180. );
  181. }
  182. static apr_status_t vt_db_fetch(apr_dbm_t *dbm, apr_datum_t key,
  183. apr_datum_t * pvalue)
  184. {
  185. DBT ckey = { 0 };
  186. DBT rd = { 0 };
  187. int dberr;
  188. ckey.data = key.dptr;
  189. ckey.size = key.dsize;
  190. dberr = do_fetch(GET_BDB(dbm->file), ckey, rd);
  191. /* "not found" is not an error. return zero'd value. */
  192. if (dberr ==
  193. #if DB_VER == 1
  194. RET_SPECIAL
  195. #else
  196. DB_NOTFOUND
  197. #endif
  198. ) {
  199. memset(&rd, 0, sizeof(rd));
  200. dberr = 0;
  201. }
  202. pvalue->dptr = rd.data;
  203. pvalue->dsize = rd.size;
  204. /* store the error info into DBM, and return a status code. Also, note
  205. that *pvalue should have been cleared on error. */
  206. return set_error(dbm, db2s(dberr));
  207. }
  208. static apr_status_t vt_db_store(apr_dbm_t *dbm, apr_datum_t key,
  209. apr_datum_t value)
  210. {
  211. apr_status_t rv;
  212. DBT ckey = { 0 };
  213. DBT cvalue = { 0 };
  214. ckey.data = key.dptr;
  215. ckey.size = key.dsize;
  216. cvalue.data = value.dptr;
  217. cvalue.size = value.dsize;
  218. rv = db2s((*GET_BDB(dbm->file)->put)(GET_BDB(dbm->file),
  219. TXN_ARG
  220. &ckey,
  221. &cvalue,
  222. 0));
  223. /* store any error info into DBM, and return a status code. */
  224. return set_error(dbm, rv);
  225. }
  226. static apr_status_t vt_db_del(apr_dbm_t *dbm, apr_datum_t key)
  227. {
  228. apr_status_t rv;
  229. DBT ckey = { 0 };
  230. ckey.data = key.dptr;
  231. ckey.size = key.dsize;
  232. rv = db2s((*GET_BDB(dbm->file)->del)(GET_BDB(dbm->file),
  233. TXN_ARG
  234. &ckey,
  235. 0));
  236. /* store any error info into DBM, and return a status code. */
  237. return set_error(dbm, rv);
  238. }
  239. static int vt_db_exists(apr_dbm_t *dbm, apr_datum_t key)
  240. {
  241. DBT ckey = { 0 }; /* converted key */
  242. DBT data = { 0 };
  243. int dberr;
  244. ckey.data = key.dptr;
  245. ckey.size = key.dsize;
  246. dberr = do_fetch(GET_BDB(dbm->file), ckey, data);
  247. /* note: the result data is "loaned" to us; we don't need to free it */
  248. /* DB returns DB_NOTFOUND if it doesn't exist. but we want to say
  249. that *any* error means it doesn't exist. */
  250. return dberr == 0;
  251. }
  252. static apr_status_t vt_db_firstkey(apr_dbm_t *dbm, apr_datum_t * pkey)
  253. {
  254. real_file_t *f = dbm->file;
  255. DBT first = { 0 };
  256. DBT data = { 0 };
  257. int dberr;
  258. #if DB_VER == 1
  259. dberr = (*f->bdb->seq)(f->bdb, &first, &data, R_FIRST);
  260. #else
  261. if ((dberr = (*f->bdb->cursor)(f->bdb, NULL, &f->curs
  262. #if DB_VER >= 3 || ((DB_VERSION_MAJOR == 2) && (DB_VERSION_MINOR > 5))
  263. , 0
  264. #endif
  265. )) == 0) {
  266. dberr = (*f->curs->c_get)(f->curs, &first, &data, DB_FIRST);
  267. if (dberr == DB_NOTFOUND) {
  268. memset(&first, 0, sizeof(first));
  269. (*f->curs->c_close)(f->curs);
  270. f->curs = NULL;
  271. dberr = 0;
  272. }
  273. }
  274. #endif
  275. pkey->dptr = first.data;
  276. pkey->dsize = first.size;
  277. /* store any error info into DBM, and return a status code. */
  278. return set_error(dbm, db2s(dberr));
  279. }
  280. static apr_status_t vt_db_nextkey(apr_dbm_t *dbm, apr_datum_t * pkey)
  281. {
  282. real_file_t *f = dbm->file;
  283. DBT ckey = { 0 };
  284. DBT data = { 0 };
  285. int dberr;
  286. ckey.data = pkey->dptr;
  287. ckey.size = pkey->dsize;
  288. #if DB_VER == 1
  289. dberr = (*f->bdb->seq)(f->bdb, &ckey, &data, R_NEXT);
  290. if (dberr == RET_SPECIAL) {
  291. dberr = 0;
  292. ckey.data = NULL;
  293. ckey.size = 0;
  294. }
  295. #else
  296. if (f->curs == NULL)
  297. return APR_EINVAL;
  298. dberr = (*f->curs->c_get)(f->curs, &ckey, &data, DB_NEXT);
  299. if (dberr == DB_NOTFOUND) {
  300. (*f->curs->c_close)(f->curs);
  301. f->curs = NULL;
  302. dberr = 0;
  303. ckey.data = NULL;
  304. ckey.size = 0;
  305. }
  306. #endif
  307. pkey->dptr = ckey.data;
  308. pkey->dsize = ckey.size;
  309. /* store any error info into DBM, and return a status code. */
  310. /* ### or use db2s(dberr) instead of APR_SUCCESS? */
  311. return set_error(dbm, APR_SUCCESS);
  312. }
  313. static void vt_db_freedatum(apr_dbm_t *dbm, apr_datum_t data)
  314. {
  315. /* nothing to do */
  316. }
  317. static void vt_db_usednames(apr_pool_t *pool, const char *pathname,
  318. const char **used1, const char **used2)
  319. {
  320. *used1 = apr_pstrdup(pool, pathname);
  321. *used2 = NULL;
  322. }
  323. APU_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_db = {
  324. "db",
  325. vt_db_open,
  326. vt_db_close,
  327. vt_db_fetch,
  328. vt_db_store,
  329. vt_db_del,
  330. vt_db_exists,
  331. vt_db_firstkey,
  332. vt_db_nextkey,
  333. vt_db_freedatum,
  334. vt_db_usednames
  335. };
  336. #endif /* APU_HAVE_DB */