xref: /PHP-8.4/ext/dba/dba_cdb.c (revision 11accb5c)
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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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 #ifdef 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