xref: /PHP-8.0/ext/dba/dba_cdb.c (revision 5d6e923d)
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    | http://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 #if 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(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 	unsigned int len;
149 	char *new_entry = NULL;
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, key, keylen) == 1) {
156 		while(skip--) {
157 			if (php_cdb_findnext(&cdb->c, key, keylen) != 1) {
158 				return NULL;
159 			}
160 		}
161 		len = cdb_datalen(&cdb->c);
162 		new_entry = safe_emalloc(len, 1, 1);
163 
164 		if (php_cdb_read(&cdb->c, new_entry, len, cdb_datapos(&cdb->c)) == -1) {
165 			efree(new_entry);
166 			return NULL;
167 		}
168 		new_entry[len] = 0;
169 		if (newlen)
170 			*newlen = len;
171 	}
172 
173 	return new_entry;
174 }
175 
DBA_UPDATE_FUNC(cdb)176 DBA_UPDATE_FUNC(cdb)
177 {
178 #if DBA_CDB_BUILTIN
179 	CDB_INFO;
180 
181 	if (!cdb->make)
182 		return FAILURE; /* database was opened readonly */
183 	if (!mode)
184 		return FAILURE; /* cdb_make doesn't know replace */
185 	if (cdb_make_add(&cdb->m, key, keylen, val, vallen) != -1)
186 		return SUCCESS;
187 #endif
188 	return FAILURE;
189 }
190 
DBA_EXISTS_FUNC(cdb)191 DBA_EXISTS_FUNC(cdb)
192 {
193 	CDB_INFO;
194 
195 #if DBA_CDB_BUILTIN
196 	if (cdb->make)
197 		return FAILURE; /* database was opened writeonly */
198 #endif
199 	if (php_cdb_find(&cdb->c, key, keylen) == 1)
200 		return SUCCESS;
201 	return FAILURE;
202 }
203 
DBA_DELETE_FUNC(cdb)204 DBA_DELETE_FUNC(cdb)
205 {
206 	return FAILURE; /* cdb doesn't support delete */
207 }
208 
209 /* {{{ cdb_file_read */
210 #if DBA_CDB_BUILTIN
211 # define cdb_file_read(fildes, buf, size) php_stream_read(fildes, buf, size)
212 #else
213 # define cdb_file_read(fildes, buf, size) read(fildes, buf, size)
214 #endif
215 /* }}} */
216 
217 #define CREAD(n) do { \
218 	if (cdb_file_read(cdb->file, buf, n) < n) return NULL; \
219 } while (0)
220 
221 /* {{{ cdb_file_lseek
222  php_stream_seek does not return actual position */
223 #if DBA_CDB_BUILTIN
cdb_file_lseek(php_stream * fp,zend_off_t offset,int whence)224 zend_off_t cdb_file_lseek(php_stream *fp, zend_off_t offset, int whence) {
225 	php_stream_seek(fp, offset, whence);
226 	return php_stream_tell(fp);
227 }
228 #else
cdb_file_lseek(int fd,zend_off_t offset,int whence)229 zend_off_t cdb_file_lseek(int fd, zend_off_t offset, int whence) {
230 	return lseek(fd, offset, whence);
231 }
232 #endif
233 /* }}} */
234 
235 #define CSEEK(n) do { \
236 	if (n >= cdb->eod) return NULL; \
237 	if (cdb_file_lseek(cdb->file, (zend_off_t)n, SEEK_SET) != (zend_off_t) n) return NULL; \
238 } while (0)
239 
240 
DBA_FIRSTKEY_FUNC(cdb)241 DBA_FIRSTKEY_FUNC(cdb)
242 {
243 	CDB_INFO;
244 	uint32 klen, dlen;
245 	char buf[8];
246 	char *key;
247 
248 #if DBA_CDB_BUILTIN
249 	if (cdb->make)
250 		return NULL; /* database was opened writeonly */
251 #endif
252 
253 	cdb->eod = -1;
254 	CSEEK(0);
255 	CREAD(4);
256 
257 	/* Total length of file in bytes */
258 	uint32_unpack(buf, &cdb->eod);
259 
260 	CSEEK(2048);
261 	CREAD(8);
262 
263 	/* The first four bytes contain the length of the key */
264 	uint32_unpack(buf, &klen);
265 	uint32_unpack(buf + 4, &dlen);
266 
267 	key = safe_emalloc(klen, 1, 1);
268 	if (cdb_file_read(cdb->file, key, klen) < klen) {
269 		efree(key);
270 		key = NULL;
271 	} else {
272 		key[klen] = '\0';
273 		if (newlen) *newlen = klen;
274 	}
275 
276 	/*       header + klenlen + dlenlen + klen + dlen */
277 	cdb->pos = 2048 + 4       + 4       + klen + dlen;
278 
279 	return key;
280 }
281 
DBA_NEXTKEY_FUNC(cdb)282 DBA_NEXTKEY_FUNC(cdb)
283 {
284 	CDB_INFO;
285 	uint32 klen, dlen;
286 	char buf[8];
287 	char *key;
288 
289 #if DBA_CDB_BUILTIN
290 	if (cdb->make)
291 		return NULL; /* database was opened writeonly */
292 #endif
293 
294 	CSEEK(cdb->pos);
295 	CREAD(8);
296 	uint32_unpack(buf, &klen);
297 	uint32_unpack(buf + 4, &dlen);
298 
299 	key = safe_emalloc(klen, 1, 1);
300 	if (cdb_file_read(cdb->file, key, klen) < klen) {
301 		efree(key);
302 		key = NULL;
303 	} else {
304 		key[klen] = '\0';
305 		if (newlen) *newlen = klen;
306 	}
307 
308 	cdb->pos += 8 + klen + dlen;
309 
310 	return key;
311 }
312 
DBA_OPTIMIZE_FUNC(cdb)313 DBA_OPTIMIZE_FUNC(cdb)
314 {
315 	return SUCCESS;
316 }
317 
DBA_SYNC_FUNC(cdb)318 DBA_SYNC_FUNC(cdb)
319 {
320 	/* this is read-only */
321 	return SUCCESS;
322 }
323 
DBA_INFO_FUNC(cdb)324 DBA_INFO_FUNC(cdb)
325 {
326 #if DBA_CDB_BUILTIN
327 	if (!strcmp(hnd->name, "cdb")) {
328 		return estrdup(cdb_version());
329 	} else {
330 		return estrdup(cdb_make_version());
331 	}
332 #else
333 	return estrdup("External");
334 #endif
335 }
336 
337 #endif
338