d9898ee8 |
1 | /* |
2 | ** Copyright 1998 - 2003 Double Precision, Inc. See COPYING for |
3 | ** distribution information. |
4 | */ |
5 | |
6 | #if HAVE_CONFIG_H |
7 | #include "config.h" |
8 | #endif |
9 | |
10 | #include <fcntl.h> |
11 | #include <string.h> |
12 | #include <stdlib.h> |
13 | #if HAVE_FCNTL_H |
14 | #include <fcntl.h> |
15 | #endif |
16 | #if HAVE_UNISTD_H |
17 | #include <unistd.h> |
18 | #endif |
19 | |
20 | #include "bdbobj.h" |
21 | |
22 | void bdbobj_init(struct bdbobj *obj) |
23 | { |
24 | obj->has_dbf=0; |
25 | |
26 | #if DB_VERSION_MAJOR >= 2 |
27 | obj->has_dbc=0; |
28 | #endif |
29 | } |
30 | |
31 | void bdbobj_close(struct bdbobj *obj) |
32 | { |
33 | #if DB_VERSION_MAJOR >= 2 |
34 | if (obj->has_dbc) |
35 | { |
36 | (*obj->dbc->c_close)(obj->dbc); |
37 | obj->has_dbc=0; |
38 | } |
39 | #endif |
40 | if ( obj->has_dbf ) |
41 | { |
42 | #if DB_VERSION_MAJOR < 2 |
43 | (*obj->dbf->close)(obj->dbf); |
44 | #else |
45 | (*obj->dbf->close)(obj->dbf, 0); |
46 | #endif |
47 | obj->has_dbf=0; |
48 | } |
49 | } |
50 | |
51 | int bdbobj_open(struct bdbobj *obj, const char *filename, const char *modestr) |
52 | { |
53 | #if DB_VERSION_MAJOR < 2 |
54 | |
55 | int flags=O_RDONLY; |
56 | |
57 | #else |
58 | |
59 | int flags=DB_RDONLY; |
60 | |
61 | #endif |
62 | |
63 | DBTYPE dbtype=DB_HASH; |
64 | |
65 | for ( ; *modestr; modestr++) |
66 | switch (*modestr) { |
67 | case 'c': |
68 | case 'C': |
69 | #if DB_VERSION_MAJOR < 2 |
70 | flags=O_RDWR|O_CREAT; |
71 | #else |
72 | flags=DB_CREATE; |
73 | #endif |
74 | break; |
75 | case 'w': |
76 | case 'W': |
77 | #if DB_VERSION_MAJOR < 2 |
78 | flags=O_RDWR; |
79 | #else |
80 | flags=0; |
81 | #endif |
82 | break; |
83 | case 'n': |
84 | case 'N': |
85 | #if DB_VERSION_MAJOR < 2 |
86 | flags=O_RDWR|O_CREAT|O_TRUNC; |
87 | #else |
88 | flags=DB_CREATE|DB_TRUNCATE; |
89 | #endif |
90 | |
91 | break; |
92 | |
93 | case 'b': |
94 | case 'B': |
95 | dbtype=DB_BTREE; |
96 | break; |
97 | |
98 | case 'e': |
99 | case 'E': |
100 | dbtype=DB_RECNO; |
101 | break; |
102 | } |
103 | |
104 | bdbobj_close(obj); |
105 | |
106 | #if DB_VERSION_MAJOR < 3 |
107 | #if DB_VERSION_MAJOR < 2 |
108 | if ( (obj->dbf=dbopen(filename, flags, 0664, dbtype, 0)) != 0) |
109 | #else |
110 | if ( db_open(filename, dbtype, flags, 0664, 0, 0, &obj->dbf) == 0) |
111 | #endif |
112 | #else |
113 | obj->dbf=0; |
114 | |
115 | #define DB_40 0 |
116 | |
117 | #if DB_VERSION_MAJOR == 4 |
118 | #if DB_VERSION_MINOR == 0 |
119 | |
120 | #undef DB_40 |
121 | #define DB_40 1 |
122 | |
123 | #endif |
124 | #endif |
125 | |
126 | #if DB_VERSION_MAJOR == 3 |
127 | #undef DB_40 |
128 | #define DB_40 1 |
129 | #endif |
130 | |
131 | if (db_create(&obj->dbf, NULL, 0) == 0) |
132 | { |
133 | if ( (*obj->dbf->open)(obj->dbf, |
134 | |
135 | #if DB_40 |
136 | |
137 | #else |
138 | NULL, |
139 | #endif |
140 | |
141 | filename, NULL, |
142 | dbtype, flags, 0664)) |
143 | { |
144 | (*obj->dbf->close)(obj->dbf, DB_NOSYNC); |
145 | obj->dbf=0; |
146 | } |
147 | } |
148 | |
149 | if (obj->dbf) |
150 | #endif |
151 | { |
152 | #ifdef FD_CLOEXEC |
153 | |
154 | #if DB_VERSION_MAJOR < 2 |
155 | int fd=(*obj->dbf->fd)(obj->dbf); |
156 | #else |
157 | int fd; |
158 | |
159 | if ((*obj->dbf->fd)(obj->dbf, &fd)) |
160 | fd= -1; |
161 | #endif |
162 | |
163 | if (fd >= 0) fcntl(fd, F_SETFD, FD_CLOEXEC); |
164 | #endif |
165 | |
166 | |
167 | obj->has_dbf=1; |
168 | return (0); |
169 | } |
170 | return (-1); |
171 | } |
172 | |
173 | int bdbobj_store(struct bdbobj *obj, const char *key, size_t keylen, |
174 | const char *data, |
175 | size_t datalen, |
176 | const char *mode) |
177 | { |
178 | DBT dkey, dval; |
179 | |
180 | memset(&dkey, 0, sizeof(dkey)); |
181 | memset(&dval, 0, sizeof(dval)); |
182 | |
183 | dkey.data=(void *)key; |
184 | dkey.size=keylen; |
185 | dval.data=(void *)data; |
186 | dval.size=datalen; |
187 | |
188 | #if DB_VERSION_MAJOR < 2 |
189 | return (obj->has_dbf ? (*obj->dbf->put)(obj->dbf, &dkey, &dval, ( |
190 | *mode == 'i' || *mode == 'I' ? R_NOOVERWRITE:0)):-1); |
191 | #else |
192 | return (obj->has_dbf ? (*obj->dbf->put)(obj->dbf, 0, &dkey, &dval, ( |
193 | *mode == 'i' || *mode == 'I' ? DB_NOOVERWRITE:0)):-1); |
194 | #endif |
195 | } |
196 | |
197 | static char *doquery(struct bdbobj *obj, |
198 | const char *, size_t, size_t *, const char *); |
199 | |
200 | char *bdbobj_fetch(struct bdbobj *obj, const char *key, size_t keylen, |
201 | size_t *datalen, const char *options) |
202 | { |
203 | char *p=doquery(obj, key, keylen, datalen, options); |
204 | char *q; |
205 | |
206 | if (!p) return (0); |
207 | |
208 | q=(char *)malloc(*datalen); |
209 | |
210 | if (!q) return (0); |
211 | |
212 | memcpy(q, p, *datalen); |
213 | return (q); |
214 | } |
215 | |
216 | char *dofetch(struct bdbobj *, const char *, size_t, size_t *); |
217 | |
218 | static char *doquery(struct bdbobj *obj, const char *key, size_t keylen, |
219 | size_t *datalen, const char *options) |
220 | { |
221 | char *p; |
222 | |
223 | for (;;) |
224 | { |
225 | if ((p=dofetch(obj, key, keylen, datalen)) != 0) |
226 | return (p); |
227 | if (!options) break; |
228 | if (*options == 'I') |
229 | { |
230 | while (keylen && key[--keylen] != '.') |
231 | ; |
232 | if (!keylen) break; |
233 | continue; |
234 | } |
235 | if (*options == 'D') |
236 | { |
237 | size_t i; |
238 | |
239 | for (i=0; i<keylen; i++) |
240 | if (key[i] == '@') { ++i; break; } |
241 | if (i < keylen) |
242 | { |
243 | if ((p=dofetch(obj, key, i, datalen)) != 0) |
244 | return (p); |
245 | key += i; |
246 | keylen -= i; |
247 | continue; |
248 | } |
249 | |
250 | for (i=0; i<keylen; i++) |
251 | if (key[i] == '.') { ++i; break; } |
252 | if (i < keylen) |
253 | { |
254 | key += i; |
255 | keylen -= i; |
256 | continue; |
257 | } |
258 | break; |
259 | } |
260 | break; |
261 | } |
262 | return (0); |
263 | } |
264 | |
265 | char *dofetch(struct bdbobj *obj, const char *key, size_t keylen, |
266 | size_t *datalen) |
267 | { |
268 | DBT dkey, val; |
269 | |
270 | if (!obj->has_dbf) return (0); |
271 | |
272 | memset(&dkey, 0, sizeof(dkey)); |
273 | memset(&val, 0, sizeof(val)); |
274 | |
275 | dkey.data=(void *)key; |
276 | dkey.size=keylen; |
277 | |
278 | #if DB_VERSION_MAJOR < 2 |
279 | if ( (*obj->dbf->get)(obj->dbf, &dkey, &val, 0)) return (0); |
280 | #else |
281 | if ( (*obj->dbf->get)(obj->dbf, 0, &dkey, &val, 0)) return (0); |
282 | #endif |
283 | |
284 | *datalen=val.size; |
285 | return ((char *)val.data); |
286 | } |
287 | |
288 | int bdbobj_exists(struct bdbobj *obj, const char *key, size_t keylen) |
289 | { |
290 | size_t datalen; |
291 | char *p=doquery(obj, key, keylen, &datalen, 0); |
292 | |
293 | return (p ? 1:0); |
294 | } |