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 #ifdef 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 typedef struct {
59 DB *dbp;
60 DBC *cursor;
61 } dba_db4_data;
62
DBA_OPEN_FUNC(db4)63 DBA_OPEN_FUNC(db4)
64 {
65 DB *dbp = NULL;
66 DBTYPE type;
67 int gmode = 0, err;
68 int filemode = info->file_permission;
69 struct stat check_stat;
70 int s = VCWD_STAT(info->path, &check_stat);
71
72 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR <= 7) /* Bug 51086 */
73 if (!s && !check_stat.st_size) {
74 info->mode = DBA_TRUNC; /* force truncate */
75 }
76
77 type = info->mode == DBA_READER ? DB_UNKNOWN :
78 info->mode == DBA_TRUNC ? DB_BTREE :
79 s ? DB_BTREE : DB_UNKNOWN;
80
81 gmode = info->mode == DBA_READER ? DB_RDONLY :
82 (info->mode == DBA_CREAT && s) ? DB_CREATE :
83 (info->mode == DBA_CREAT && !s) ? 0 :
84 info->mode == DBA_WRITER ? 0 :
85 info->mode == DBA_TRUNC ? DB_CREATE | DB_TRUNCATE : -1;
86 #else
87 if (!s && !check_stat.st_size) {
88 info->mode = DBA_CREAT; /* force creation */
89 }
90
91 type = info->mode == DBA_READER ? DB_UNKNOWN :
92 (info->mode == DBA_TRUNC || info->mode == DBA_CREAT) ? DB_BTREE :
93 s ? DB_BTREE : DB_UNKNOWN;
94
95 gmode = info->mode == DBA_READER ? DB_RDONLY :
96 info->mode == DBA_CREAT ? DB_CREATE :
97 info->mode == DBA_WRITER ? 0 :
98 info->mode == DBA_TRUNC ? DB_CREATE | DB_TRUNCATE : -1;
99 #endif
100
101 if (gmode == -1) {
102 return FAILURE; /* not possible */
103 }
104
105 if (info->flags & DBA_PERSISTENT) {
106 gmode |= DB_THREAD;
107 }
108
109 if ((err=db_create(&dbp, NULL, 0)) == 0) {
110 dbp->set_errcall(dbp, php_dba_db4_errcall_fcn);
111 if (
112 #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1))
113 (err=dbp->open(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) {
114 #else
115 (err=dbp->open(dbp, info->path, NULL, type, gmode, filemode)) == 0) {
116 #endif
117 dba_db4_data *data;
118
119 data = pemalloc(sizeof(*data), info->flags&DBA_PERSISTENT);
120 data->dbp = dbp;
121 data->cursor = NULL;
122 info->dbf = data;
123
124 return SUCCESS;
125 } else {
126 dbp->close(dbp, 0);
127 *error = db_strerror(err);
128 }
129 } else {
130 *error = db_strerror(err);
131 }
132
133 return FAILURE;
134 }
135
136 DBA_CLOSE_FUNC(db4)
137 {
138 dba_db4_data *dba = info->dbf;
139
140 if (dba->cursor) dba->cursor->c_close(dba->cursor);
141 dba->dbp->close(dba->dbp, 0);
142 pefree(dba, info->flags&DBA_PERSISTENT);
143 }
144
145 DBA_FETCH_FUNC(db4)
146 {
147 dba_db4_data *dba = info->dbf;
148 DBT gval;
149 DBT gkey;
150 zend_string *fetched_value = NULL;
151
152 memset(&gkey, 0, sizeof(gkey));
153 gkey.data = ZSTR_VAL(key);
154 gkey.size = ZSTR_LEN(key);
155
156 memset(&gval, 0, sizeof(gval));
157 if (info->flags & DBA_PERSISTENT) {
158 gval.flags |= DB_DBT_MALLOC;
159 }
160 if (!dba->dbp->get(dba->dbp, NULL, &gkey, &gval, 0)) {
161 fetched_value = zend_string_init(gval.data, gval.size, /* persistent */ false);
162 if (info->flags & DBA_PERSISTENT) {
163 free(gval.data);
164 }
165 }
166 return fetched_value;
167 }
168
169 DBA_UPDATE_FUNC(db4)
170 {
171 dba_db4_data *dba = info->dbf;
172 DBT gval;
173 DBT gkey;
174
175 memset(&gkey, 0, sizeof(gkey));
176 gkey.data = ZSTR_VAL(key);
177 gkey.size = ZSTR_LEN(key);
178
179 memset(&gval, 0, sizeof(gval));
180 gval.data = ZSTR_VAL(val);
181 gval.size = ZSTR_LEN(val);
182
183 if (!dba->dbp->put(dba->dbp, NULL, &gkey, &gval,
184 mode == 1 ? DB_NOOVERWRITE : 0)) {
185 return SUCCESS;
186 }
187 return FAILURE;
188 }
189
190 DBA_EXISTS_FUNC(db4)
191 {
192 dba_db4_data *dba = info->dbf;
193 DBT gval;
194 DBT gkey;
195
196 memset(&gkey, 0, sizeof(gkey));
197 gkey.data = ZSTR_VAL(key);
198 gkey.size = ZSTR_LEN(key);
199
200 memset(&gval, 0, sizeof(gval));
201
202 if (info->flags & DBA_PERSISTENT) {
203 gval.flags |= DB_DBT_MALLOC;
204 }
205
206 if (!dba->dbp->get(dba->dbp, NULL, &gkey, &gval, 0)) {
207 if (info->flags & DBA_PERSISTENT) {
208 free(gval.data);
209 }
210 return SUCCESS;
211 }
212 return FAILURE;
213 }
214
215 DBA_DELETE_FUNC(db4)
216 {
217 dba_db4_data *dba = info->dbf;
218 DBT gkey;
219
220 memset(&gkey, 0, sizeof(gkey));
221 gkey.data = ZSTR_VAL(key);
222 gkey.size = ZSTR_LEN(key);
223
224 return dba->dbp->del(dba->dbp, NULL, &gkey, 0) ? FAILURE : SUCCESS;
225 }
226
227 DBA_FIRSTKEY_FUNC(db4)
228 {
229 dba_db4_data *dba = info->dbf;
230
231 if (dba->cursor) {
232 dba->cursor->c_close(dba->cursor);
233 }
234
235 dba->cursor = NULL;
236 if (dba->dbp->cursor(dba->dbp, NULL, &dba->cursor, 0) != 0) {
237 return NULL;
238 }
239
240 return dba_nextkey_db4(info);
241 }
242
243 DBA_NEXTKEY_FUNC(db4)
244 {
245 dba_db4_data *dba = info->dbf;
246 DBT gkey, gval;
247 zend_string *key = NULL;
248
249 memset(&gkey, 0, sizeof(gkey));
250 memset(&gval, 0, sizeof(gval));
251
252 if (info->flags & DBA_PERSISTENT) {
253 gkey.flags |= DB_DBT_MALLOC;
254 gval.flags |= DB_DBT_MALLOC;
255 }
256 if (dba->cursor && dba->cursor->c_get(dba->cursor, &gkey, &gval, DB_NEXT) == 0) {
257 if (gkey.data) {
258 key = zend_string_init(gkey.data, gkey.size, /* persistent */ false);
259 }
260 if (info->flags & DBA_PERSISTENT) {
261 if (gkey.data) {
262 free(gkey.data);
263 }
264 if (gval.data) {
265 free(gval.data);
266 }
267 }
268 }
269
270 return key;
271 }
272
273 DBA_OPTIMIZE_FUNC(db4)
274 {
275 return SUCCESS;
276 }
277
278 DBA_SYNC_FUNC(db4)
279 {
280 dba_db4_data *dba = info->dbf;
281
282 return dba->dbp->sync(dba->dbp, 0) ? FAILURE : SUCCESS;
283 }
284
285 DBA_INFO_FUNC(db4)
286 {
287 return estrdup(DB_VERSION_STRING);
288 }
289
290 #endif
291