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