1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Marcus Boerger <helly@php.net> |
14 | Sascha Schumann <sascha@schumann.cx> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23
24 #if DBA_DB4
25 #include "php_db4.h"
26 #include <sys/stat.h>
27
28 #include <string.h>
29 #ifdef DB4_INCLUDE_FILE
30 #include DB4_INCLUDE_FILE
31 #else
32 #include <db.h>
33 #endif
34
php_dba_db4_errcall_fcn(const DB_ENV * dbenv,const char * errpfx,const char * msg)35 static void php_dba_db4_errcall_fcn(
36 #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3))
37 const DB_ENV *dbenv,
38 #endif
39 const char *errpfx, const char *msg)
40 {
41
42 #if (DB_VERSION_MAJOR == 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8))
43 /* Bug 51086, Berkeley DB 4.8.26 */
44 /* This code suppresses a BDB 4.8+ error message, thus keeping PHP test compatibility */
45 {
46 const char *function = get_active_function_name();
47 if (function && (!strcmp(function,"dba_popen") || !strcmp(function,"dba_open"))
48 && (!strncmp(msg, "fop_read_meta", sizeof("fop_read_meta")-1)
49 || !strncmp(msg, "BDB0004 fop_read_meta", sizeof("BDB0004 fop_read_meta")-1))) {
50 return;
51 }
52 }
53 #endif
54
55 php_error_docref(NULL, E_NOTICE, "%s%s", errpfx?errpfx:"", msg);
56 }
57
58 #define DB4_DATA dba_db4_data *dba = info->dbf
59 #define DB4_GKEY \
60 DBT gkey; \
61 memset(&gkey, 0, sizeof(gkey)); \
62 gkey.data = (char *) key; gkey.size = keylen
63
64 typedef struct {
65 DB *dbp;
66 DBC *cursor;
67 } dba_db4_data;
68
DBA_OPEN_FUNC(db4)69 DBA_OPEN_FUNC(db4)
70 {
71 DB *dbp = NULL;
72 DBTYPE type;
73 int gmode = 0, err;
74 int filemode = 0644;
75 struct stat check_stat;
76 int s = VCWD_STAT(info->path, &check_stat);
77
78 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 7) /* Bug 51086 */
79 if (!s && !check_stat.st_size) {
80 info->mode = DBA_TRUNC; /* force truncate */
81 }
82
83 type = info->mode == DBA_READER ? DB_UNKNOWN :
84 info->mode == DBA_TRUNC ? DB_BTREE :
85 s ? DB_BTREE : DB_UNKNOWN;
86
87 gmode = info->mode == DBA_READER ? DB_RDONLY :
88 (info->mode == DBA_CREAT && s) ? DB_CREATE :
89 (info->mode == DBA_CREAT && !s) ? 0 :
90 info->mode == DBA_WRITER ? 0 :
91 info->mode == DBA_TRUNC ? DB_CREATE | DB_TRUNCATE : -1;
92 #else
93 if (!s && !check_stat.st_size) {
94 info->mode = DBA_CREAT; /* force creation */
95 }
96
97 type = info->mode == DBA_READER ? DB_UNKNOWN :
98 (info->mode == DBA_TRUNC || info->mode == DBA_CREAT) ? DB_BTREE :
99 s ? DB_BTREE : DB_UNKNOWN;
100
101 gmode = info->mode == DBA_READER ? DB_RDONLY :
102 info->mode == DBA_CREAT ? DB_CREATE :
103 info->mode == DBA_WRITER ? 0 :
104 info->mode == DBA_TRUNC ? DB_CREATE | DB_TRUNCATE : -1;
105 #endif
106
107 if (gmode == -1) {
108 return FAILURE; /* not possible */
109 }
110
111 if (info->flags & DBA_PERSISTENT) {
112 gmode |= DB_THREAD;
113 }
114
115 if (info->argc > 0) {
116 filemode = zval_get_long(&info->argv[0]);
117 }
118
119 if ((err=db_create(&dbp, NULL, 0)) == 0) {
120 dbp->set_errcall(dbp, php_dba_db4_errcall_fcn);
121 if (
122 #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1))
123 (err=dbp->open(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) {
124 #else
125 (err=dbp->open(dbp, info->path, NULL, type, gmode, filemode)) == 0) {
126 #endif
127 dba_db4_data *data;
128
129 data = pemalloc(sizeof(*data), info->flags&DBA_PERSISTENT);
130 data->dbp = dbp;
131 data->cursor = NULL;
132 info->dbf = data;
133
134 return SUCCESS;
135 } else {
136 dbp->close(dbp, 0);
137 *error = db_strerror(err);
138 }
139 } else {
140 *error = db_strerror(err);
141 }
142
143 return FAILURE;
144 }
145
146 DBA_CLOSE_FUNC(db4)
147 {
148 DB4_DATA;
149
150 if (dba->cursor) dba->cursor->c_close(dba->cursor);
151 dba->dbp->close(dba->dbp, 0);
152 pefree(dba, info->flags&DBA_PERSISTENT);
153 }
154
155 DBA_FETCH_FUNC(db4)
156 {
157 DBT gval;
158 char *new = NULL;
159 DB4_DATA;
160 DB4_GKEY;
161
162 memset(&gval, 0, sizeof(gval));
163 if (info->flags & DBA_PERSISTENT) {
164 gval.flags |= DB_DBT_MALLOC;
165 }
166 if (!dba->dbp->get(dba->dbp, NULL, &gkey, &gval, 0)) {
167 if (newlen) *newlen = gval.size;
168 new = estrndup(gval.data, gval.size);
169 if (info->flags & DBA_PERSISTENT) {
170 free(gval.data);
171 }
172 }
173 return new;
174 }
175
176 DBA_UPDATE_FUNC(db4)
177 {
178 DBT gval;
179 DB4_DATA;
180 DB4_GKEY;
181
182 memset(&gval, 0, sizeof(gval));
183 gval.data = (char *) val;
184 gval.size = vallen;
185
186 if (!dba->dbp->put(dba->dbp, NULL, &gkey, &gval,
187 mode == 1 ? DB_NOOVERWRITE : 0)) {
188 return SUCCESS;
189 }
190 return FAILURE;
191 }
192
193 DBA_EXISTS_FUNC(db4)
194 {
195 DBT gval;
196 DB4_DATA;
197 DB4_GKEY;
198
199 memset(&gval, 0, sizeof(gval));
200
201 if (info->flags & DBA_PERSISTENT) {
202 gval.flags |= DB_DBT_MALLOC;
203 }
204
205 if (!dba->dbp->get(dba->dbp, NULL, &gkey, &gval, 0)) {
206 if (info->flags & DBA_PERSISTENT) {
207 free(gval.data);
208 }
209 return SUCCESS;
210 }
211 return FAILURE;
212 }
213
214 DBA_DELETE_FUNC(db4)
215 {
216 DB4_DATA;
217 DB4_GKEY;
218
219 return dba->dbp->del(dba->dbp, NULL, &gkey, 0) ? FAILURE : SUCCESS;
220 }
221
222 DBA_FIRSTKEY_FUNC(db4)
223 {
224 DB4_DATA;
225
226 if (dba->cursor) {
227 dba->cursor->c_close(dba->cursor);
228 }
229
230 dba->cursor = NULL;
231 if (dba->dbp->cursor(dba->dbp, NULL, &dba->cursor, 0) != 0) {
232 return NULL;
233 }
234
235 /* we should introduce something like PARAM_PASSTHRU... */
236 return dba_nextkey_db4(info, newlen);
237 }
238
239 DBA_NEXTKEY_FUNC(db4)
240 {
241 DB4_DATA;
242 DBT gkey, gval;
243 char *nkey = NULL;
244
245 memset(&gkey, 0, sizeof(gkey));
246 memset(&gval, 0, sizeof(gval));
247
248 if (info->flags & DBA_PERSISTENT) {
249 gkey.flags |= DB_DBT_MALLOC;
250 gval.flags |= DB_DBT_MALLOC;
251 }
252 if (dba->cursor && dba->cursor->c_get(dba->cursor, &gkey, &gval, DB_NEXT) == 0) {
253 if (gkey.data) {
254 nkey = estrndup(gkey.data, gkey.size);
255 if (newlen) *newlen = gkey.size;
256 }
257 if (info->flags & DBA_PERSISTENT) {
258 if (gkey.data) {
259 free(gkey.data);
260 }
261 if (gval.data) {
262 free(gval.data);
263 }
264 }
265 }
266
267 return nkey;
268 }
269
270 DBA_OPTIMIZE_FUNC(db4)
271 {
272 return SUCCESS;
273 }
274
275 DBA_SYNC_FUNC(db4)
276 {
277 DB4_DATA;
278
279 return dba->dbp->sync(dba->dbp, 0) ? FAILURE : SUCCESS;
280 }
281
282 DBA_INFO_FUNC(db4)
283 {
284 return estrdup(DB_VERSION_STRING);
285 }
286
287 #endif
288