xref: /PHP-5.6/ext/dba/dba_cdb.c (revision 49493a2d)
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