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: Sascha Schumann <sascha@schumann.cx> |
14 | Marcus Boerger <helly@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23
24 #ifdef DBA_CDB
25 #include "php_cdb.h"
26
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <fcntl.h>
32
33 #if DBA_CDB_BUILTIN
34 # include "libcdb/cdb.h"
35 # include "libcdb/cdb_make.h"
36 # include "libcdb/uint32.h"
37 #else
38 # ifdef CDB_INCLUDE_FILE
39 # include CDB_INCLUDE_FILE
40 # endif
41 #endif
42
43 #define CDB_INFO \
44 dba_cdb *cdb = (dba_cdb *) info->dbf
45
46 typedef struct {
47 struct cdb c;
48 #if DBA_CDB_BUILTIN
49 struct cdb_make m;
50 php_stream *file;
51 int make;
52 #else
53 int file;
54 #endif
55 uint32 eod; /* size of constant database */
56 uint32 pos; /* current position for traversing */
57 } dba_cdb;
58
DBA_OPEN_FUNC(cdb)59 DBA_OPEN_FUNC(cdb)
60 {
61 #if DBA_CDB_BUILTIN
62 php_stream* file = 0;
63 int make;
64 #else
65 int file = 0;
66 #endif
67 dba_cdb *cdb;
68 dba_info *pinfo = (dba_info *) info;
69
70 switch (info->mode) {
71 case DBA_READER:
72 #if DBA_CDB_BUILTIN
73 make = 0;
74 file = info->fp;
75 #else
76 file = VCWD_OPEN(ZSTR_VAL(info->path), O_RDONLY);
77 if (file < 0) {
78 *error = "Unable to open file";
79 return FAILURE;
80 }
81 #endif
82 break;
83 #if DBA_CDB_BUILTIN
84 case DBA_TRUNC:
85 make = 1;
86 file = info->fp;
87 break;
88 case DBA_CREAT:
89 case DBA_WRITER:
90 *error = "Update operations are not supported";
91 return FAILURE; /* not supported */
92 #endif
93 default:
94 *error = "Currently not supported";
95 return FAILURE;
96 }
97
98 cdb = pemalloc(sizeof(dba_cdb), info->flags&DBA_PERSISTENT);
99 memset(cdb, 0, sizeof(dba_cdb));
100
101 #if DBA_CDB_BUILTIN
102 if (make) {
103 cdb_make_start(&cdb->m, file);
104 } else {
105 cdb_init(&cdb->c, file);
106 }
107 cdb->make = make;
108 #else
109 cdb_init(&cdb->c, file);
110 #endif
111 cdb->file = file;
112
113 pinfo->dbf = cdb;
114 return SUCCESS;
115 }
116
DBA_CLOSE_FUNC(cdb)117 DBA_CLOSE_FUNC(cdb)
118 {
119 CDB_INFO;
120
121 /* cdb_free does not close associated file */
122 #if DBA_CDB_BUILTIN
123 if (cdb->make) {
124 cdb_make_finish(&cdb->m);
125 } else {
126 cdb_free(&cdb->c);
127 }
128 #else
129 cdb_free(&cdb->c);
130 close(cdb->file);
131 #endif
132 pefree(cdb, info->flags&DBA_PERSISTENT);
133 }
134
135 #if DBA_CDB_BUILTIN
136 # define php_cdb_read(cdb, buf, len, pos) cdb_read(cdb, buf, len, pos)
137 # define php_cdb_findnext(cdb, key, len) cdb_findnext(cdb, key, len)
138 # define php_cdb_find(cdb, key, len) cdb_find(cdb, key, len)
139 #else
140 # define php_cdb_read(cdb, buf, len, pos) cdb_read(cdb, buf, len, pos)
141 # define php_cdb_findnext(cdb, key, len) cdb_findnext(cdb, key, len)
142 # define php_cdb_find(cdb, key, len) cdb_find(cdb, key, len)
143 #endif
144
DBA_FETCH_FUNC(cdb)145 DBA_FETCH_FUNC(cdb)
146 {
147 CDB_INFO;
148 zend_string *fetched_val = NULL;
149 unsigned int len;
150
151 #if DBA_CDB_BUILTIN
152 if (cdb->make)
153 return NULL; /* database was opened writeonly */
154 #endif
155 if (php_cdb_find(&cdb->c, ZSTR_VAL(key), ZSTR_LEN(key)) == 1) {
156 while(skip--) {
157 if (php_cdb_findnext(&cdb->c, ZSTR_VAL(key), ZSTR_LEN(key)) != 1) {
158 return NULL;
159 }
160 }
161 len = cdb_datalen(&cdb->c);
162 fetched_val = zend_string_alloc(len, /* persistent */ false);
163
164 if (php_cdb_read(&cdb->c, ZSTR_VAL(fetched_val), len, cdb_datapos(&cdb->c)) == -1) {
165 zend_string_release_ex(fetched_val, /* persistent */ false);
166 return NULL;
167 }
168 ZSTR_VAL(fetched_val)[len] = 0;
169 }
170
171 return fetched_val;
172 }
173
DBA_UPDATE_FUNC(cdb)174 DBA_UPDATE_FUNC(cdb)
175 {
176 #if DBA_CDB_BUILTIN
177 CDB_INFO;
178
179 if (!cdb->make)
180 return FAILURE; /* database was opened readonly */
181 if (!mode)
182 return FAILURE; /* cdb_make doesn't know replace */
183 if (cdb_make_add(&cdb->m, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(val), ZSTR_LEN(val)) != -1)
184 return SUCCESS;
185 #endif
186 return FAILURE;
187 }
188
DBA_EXISTS_FUNC(cdb)189 DBA_EXISTS_FUNC(cdb)
190 {
191 CDB_INFO;
192
193 #if DBA_CDB_BUILTIN
194 if (cdb->make)
195 return FAILURE; /* database was opened writeonly */
196 #endif
197 if (php_cdb_find(&cdb->c, ZSTR_VAL(key), ZSTR_LEN(key)) == 1)
198 return SUCCESS;
199 return FAILURE;
200 }
201
DBA_DELETE_FUNC(cdb)202 DBA_DELETE_FUNC(cdb)
203 {
204 return FAILURE; /* cdb doesn't support delete */
205 }
206
207 /* {{{ cdb_file_read */
208 #if DBA_CDB_BUILTIN
209 # define cdb_file_read(fildes, buf, size) php_stream_read(fildes, buf, size)
210 #else
211 # define cdb_file_read(fildes, buf, size) read(fildes, buf, size)
212 #endif
213 /* }}} */
214
215 #define CREAD(n) do { \
216 if (cdb_file_read(cdb->file, buf, n) < n) return NULL; \
217 } while (0)
218
219 /* {{{ cdb_file_lseek
220 php_stream_seek does not return actual position */
221 #if DBA_CDB_BUILTIN
cdb_file_lseek(php_stream * fp,zend_off_t offset,int whence)222 zend_off_t cdb_file_lseek(php_stream *fp, zend_off_t offset, int whence) {
223 php_stream_seek(fp, offset, whence);
224 return php_stream_tell(fp);
225 }
226 #else
cdb_file_lseek(int fd,zend_off_t offset,int whence)227 zend_off_t cdb_file_lseek(int fd, zend_off_t offset, int whence) {
228 return lseek(fd, offset, whence);
229 }
230 #endif
231 /* }}} */
232
233 #define CSEEK(n) do { \
234 if (n >= cdb->eod) return NULL; \
235 if (cdb_file_lseek(cdb->file, (zend_off_t)n, SEEK_SET) != (zend_off_t) n) return NULL; \
236 } while (0)
237
238
DBA_FIRSTKEY_FUNC(cdb)239 DBA_FIRSTKEY_FUNC(cdb)
240 {
241 CDB_INFO;
242 uint32 klen, dlen;
243 char buf[8];
244 zend_string *key;
245
246 #if DBA_CDB_BUILTIN
247 if (cdb->make)
248 return NULL; /* database was opened writeonly */
249 #endif
250
251 cdb->eod = -1;
252 CSEEK(0);
253 CREAD(4);
254
255 /* Total length of file in bytes */
256 uint32_unpack(buf, &cdb->eod);
257
258 CSEEK(2048);
259 CREAD(8);
260
261 /* The first four bytes contain the length of the key */
262 uint32_unpack(buf, &klen);
263 uint32_unpack(buf + 4, &dlen);
264
265 key = zend_string_alloc(klen, /* persistent */ false);
266 if (cdb_file_read(cdb->file, ZSTR_VAL(key), klen) < klen) {
267 zend_string_release_ex(key, /* persistent */ false);
268 key = NULL;
269 } else {
270 ZSTR_VAL(key)[klen] = 0;
271 }
272
273 /* header + klenlen + dlenlen + klen + dlen */
274 cdb->pos = 2048 + 4 + 4 + klen + dlen;
275
276 return key;
277 }
278
DBA_NEXTKEY_FUNC(cdb)279 DBA_NEXTKEY_FUNC(cdb)
280 {
281 CDB_INFO;
282 uint32 klen, dlen;
283 char buf[8];
284 zend_string *key;
285
286 #if DBA_CDB_BUILTIN
287 if (cdb->make)
288 return NULL; /* database was opened writeonly */
289 #endif
290
291 CSEEK(cdb->pos);
292 CREAD(8);
293 uint32_unpack(buf, &klen);
294 uint32_unpack(buf + 4, &dlen);
295
296 key = zend_string_alloc(klen, /* persistent */ false);
297 if (cdb_file_read(cdb->file, ZSTR_VAL(key), klen) < klen) {
298 zend_string_release_ex(key, /* persistent */ false);
299 key = NULL;
300 } else {
301 ZSTR_VAL(key)[klen] = 0;
302 }
303
304 cdb->pos += 8 + klen + dlen;
305
306 return key;
307 }
308
DBA_OPTIMIZE_FUNC(cdb)309 DBA_OPTIMIZE_FUNC(cdb)
310 {
311 return SUCCESS;
312 }
313
DBA_SYNC_FUNC(cdb)314 DBA_SYNC_FUNC(cdb)
315 {
316 /* this is read-only */
317 return SUCCESS;
318 }
319
DBA_INFO_FUNC(cdb)320 DBA_INFO_FUNC(cdb)
321 {
322 #if DBA_CDB_BUILTIN
323 if (!strcmp(hnd->name, "cdb")) {
324 return estrdup(cdb_version());
325 } else {
326 return estrdup(cdb_make_version());
327 }
328 #else
329 return estrdup("External");
330 #endif
331 }
332
333 #endif
334