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