xref: /PHP-7.2/ext/dba/dba.c (revision 7a7ec01a)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 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 HAVE_DBA
29 
30 #include "php_ini.h"
31 #include <stdio.h>
32 #include <fcntl.h>
33 #ifdef HAVE_SYS_FILE_H
34 #include <sys/file.h>
35 #endif
36 
37 #include "php_dba.h"
38 #include "ext/standard/info.h"
39 #include "ext/standard/php_string.h"
40 #include "ext/standard/flock_compat.h"
41 
42 #include "php_gdbm.h"
43 #include "php_ndbm.h"
44 #include "php_dbm.h"
45 #include "php_cdb.h"
46 #include "php_db1.h"
47 #include "php_db2.h"
48 #include "php_db3.h"
49 #include "php_db4.h"
50 #include "php_flatfile.h"
51 #include "php_inifile.h"
52 #include "php_qdbm.h"
53 #include "php_tcadb.h"
54 #include "php_lmdb.h"
55 
56 /* {{{ arginfo */
57 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_popen, 0, 0, 2)
58 	ZEND_ARG_INFO(0, path)
59 	ZEND_ARG_INFO(0, mode)
60 	ZEND_ARG_INFO(0, handlername)
61 	ZEND_ARG_VARIADIC_INFO(0, handler_parameters)
62 ZEND_END_ARG_INFO()
63 
64 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_open, 0, 0, 2)
65 	ZEND_ARG_INFO(0, path)
66 	ZEND_ARG_INFO(0, mode)
67 	ZEND_ARG_INFO(0, handlername)
68 	ZEND_ARG_VARIADIC_INFO(0, handler_parameters)
69 ZEND_END_ARG_INFO()
70 
71 ZEND_BEGIN_ARG_INFO(arginfo_dba_close, 0)
72 	ZEND_ARG_INFO(0, handle)
73 ZEND_END_ARG_INFO()
74 
75 ZEND_BEGIN_ARG_INFO(arginfo_dba_exists, 0)
76 	ZEND_ARG_INFO(0, key)
77 	ZEND_ARG_INFO(0, handle)
78 ZEND_END_ARG_INFO()
79 
80 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_fetch, 0, 0, 2)
81 	ZEND_ARG_INFO(0, key)
82 	ZEND_ARG_INFO(0, skip)
83 	ZEND_ARG_INFO(0, handle)
84 ZEND_END_ARG_INFO()
85 
86 ZEND_BEGIN_ARG_INFO(arginfo_dba_key_split, 0)
87 	ZEND_ARG_INFO(0, key)
88 ZEND_END_ARG_INFO()
89 
90 ZEND_BEGIN_ARG_INFO(arginfo_dba_firstkey, 0)
91 	ZEND_ARG_INFO(0, handle)
92 ZEND_END_ARG_INFO()
93 
94 ZEND_BEGIN_ARG_INFO(arginfo_dba_nextkey, 0)
95 	ZEND_ARG_INFO(0, handle)
96 ZEND_END_ARG_INFO()
97 
98 ZEND_BEGIN_ARG_INFO(arginfo_dba_delete, 0)
99 	ZEND_ARG_INFO(0, key)
100 	ZEND_ARG_INFO(0, handle)
101 ZEND_END_ARG_INFO()
102 
103 ZEND_BEGIN_ARG_INFO(arginfo_dba_insert, 0)
104 	ZEND_ARG_INFO(0, key)
105 	ZEND_ARG_INFO(0, value)
106 	ZEND_ARG_INFO(0, handle)
107 ZEND_END_ARG_INFO()
108 
109 ZEND_BEGIN_ARG_INFO(arginfo_dba_replace, 0)
110 	ZEND_ARG_INFO(0, key)
111 	ZEND_ARG_INFO(0, value)
112 	ZEND_ARG_INFO(0, handle)
113 ZEND_END_ARG_INFO()
114 
115 ZEND_BEGIN_ARG_INFO(arginfo_dba_optimize, 0)
116 	ZEND_ARG_INFO(0, handle)
117 ZEND_END_ARG_INFO()
118 
119 ZEND_BEGIN_ARG_INFO(arginfo_dba_sync, 0)
120 	ZEND_ARG_INFO(0, handle)
121 ZEND_END_ARG_INFO()
122 
123 ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_handlers, 0, 0, 0)
124 	ZEND_ARG_INFO(0, full_info)
125 ZEND_END_ARG_INFO()
126 
127 ZEND_BEGIN_ARG_INFO(arginfo_dba_list, 0)
128 ZEND_END_ARG_INFO()
129 
130 /* }}} */
131 
132 /* {{{ dba_functions[]
133  */
134 const zend_function_entry dba_functions[] = {
135 	PHP_FE(dba_open, arginfo_dba_open)
136 	PHP_FE(dba_popen, arginfo_dba_popen)
137 	PHP_FE(dba_close, arginfo_dba_close)
138 	PHP_FE(dba_delete, arginfo_dba_delete)
139 	PHP_FE(dba_exists, arginfo_dba_exists)
140 	PHP_FE(dba_fetch, arginfo_dba_fetch)
141 	PHP_FE(dba_insert, arginfo_dba_insert)
142 	PHP_FE(dba_replace, arginfo_dba_replace)
143 	PHP_FE(dba_firstkey, arginfo_dba_firstkey)
144 	PHP_FE(dba_nextkey, arginfo_dba_nextkey)
145 	PHP_FE(dba_optimize, arginfo_dba_optimize)
146 	PHP_FE(dba_sync, arginfo_dba_sync)
147 	PHP_FE(dba_handlers, arginfo_dba_handlers)
148 	PHP_FE(dba_list, arginfo_dba_list)
149 	PHP_FE(dba_key_split, arginfo_dba_key_split)
150 	PHP_FE_END
151 };
152 /* }}} */
153 
154 PHP_MINIT_FUNCTION(dba);
155 PHP_MSHUTDOWN_FUNCTION(dba);
156 PHP_MINFO_FUNCTION(dba);
157 
158 ZEND_BEGIN_MODULE_GLOBALS(dba)
159 	char *default_handler;
160 	dba_handler *default_hptr;
161 ZEND_END_MODULE_GLOBALS(dba)
162 
163 ZEND_DECLARE_MODULE_GLOBALS(dba)
164 
165 #ifdef ZTS
166 #define DBA_G(v) TSRMG(dba_globals_id, zend_dba_globals *, v)
167 #else
168 #define DBA_G(v) (dba_globals.v)
169 #endif
170 
171 static PHP_GINIT_FUNCTION(dba);
172 
173 zend_module_entry dba_module_entry = {
174 	STANDARD_MODULE_HEADER,
175 	"dba",
176 	dba_functions,
177 	PHP_MINIT(dba),
178 	PHP_MSHUTDOWN(dba),
179 	NULL,
180 	NULL,
181 	PHP_MINFO(dba),
182 	PHP_DBA_VERSION,
183 	PHP_MODULE_GLOBALS(dba),
184 	PHP_GINIT(dba),
185 	NULL,
186 	NULL,
187 	STANDARD_MODULE_PROPERTIES_EX
188 };
189 
190 #ifdef COMPILE_DL_DBA
ZEND_GET_MODULE(dba)191 ZEND_GET_MODULE(dba)
192 #endif
193 
194 /* {{{ macromania */
195 
196 #define DBA_ID_PARS 											\
197 	zval *id; 													\
198 	dba_info *info = NULL; 										\
199 	int ac = ZEND_NUM_ARGS()
200 
201 /* these are used to get the standard arguments */
202 
203 /* {{{ php_dba_myke_key */
204 static size_t php_dba_make_key(zval *key, char **key_str, char **key_free)
205 {
206 	if (Z_TYPE_P(key) == IS_ARRAY) {
207 		zval *group, *name;
208 		HashPosition pos;
209 		size_t len;
210 
211 		if (zend_hash_num_elements(Z_ARRVAL_P(key)) != 2) {
212 			zend_throw_error(NULL, "Key does not have exactly two elements: (key, name)");
213 			return 0;
214 		}
215 		zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(key), &pos);
216 		group = zend_hash_get_current_data_ex(Z_ARRVAL_P(key), &pos);
217 		zend_hash_move_forward_ex(Z_ARRVAL_P(key), &pos);
218 		name = zend_hash_get_current_data_ex(Z_ARRVAL_P(key), &pos);
219 		convert_to_string_ex(group);
220 		convert_to_string_ex(name);
221 		if (Z_STRLEN_P(group) == 0) {
222 			*key_str = Z_STRVAL_P(name);
223 			*key_free = NULL;
224 			return Z_STRLEN_P(name);
225 		}
226 		len = spprintf(key_str, 0, "[%s]%s", Z_STRVAL_P(group), Z_STRVAL_P(name));
227 		*key_free = *key_str;
228 		return len;
229 	} else {
230 		zval tmp;
231 		size_t len;
232 
233 		ZVAL_COPY(&tmp, key);
234 		convert_to_string(&tmp);
235 
236 		len = Z_STRLEN(tmp);
237 		if (len) {
238 			*key_free = *key_str = estrndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
239 		}
240 		zval_ptr_dtor(&tmp);
241 		return len;
242 	}
243 }
244 /* }}} */
245 
246 #define DBA_GET2 												\
247 	zval *key;													\
248 	char *key_str, *key_free;									\
249 	size_t key_len; 											\
250 	if (zend_parse_parameters(ac, "zr", &key, &id) == FAILURE) { 	\
251 		return; 												\
252 	} 															\
253 	if ((key_len = php_dba_make_key(key, &key_str, &key_free)) == 0) {\
254 		RETURN_FALSE;											\
255 	}
256 
257 #define DBA_GET2_3												\
258 	zval *key;													\
259 	char *key_str, *key_free;									\
260 	size_t key_len; 											\
261 	zend_long skip = 0;  											\
262 	switch(ac) {												\
263 	case 2: 													\
264 		if (zend_parse_parameters(ac, "zr", &key, &id) == FAILURE) { \
265 			return;												\
266 		} 														\
267 		break;  												\
268 	case 3: 													\
269 		if (zend_parse_parameters(ac, "zlr", &key, &skip, &id) == FAILURE) { \
270 			return;												\
271 		} 														\
272 		break;  												\
273 	default:													\
274 		WRONG_PARAM_COUNT; 										\
275 	} 															\
276 	if ((key_len = php_dba_make_key(key, &key_str, &key_free)) == 0) {\
277 		RETURN_FALSE;											\
278 	}
279 
280 
281 #define DBA_FETCH_RESOURCE(info, id)	\
282 	if ((info = (dba_info *)zend_fetch_resource2(Z_RES_P(id), "DBA identifier", le_db, le_pdb)) == NULL) { \
283 		RETURN_FALSE; \
284 	}
285 
286 #define DBA_FETCH_RESOURCE_WITH_ID(info, id)	\
287 	if ((info = (dba_info *)zend_fetch_resource2(Z_RES_P(id), "DBA identifier", le_db, le_pdb)) == NULL) { \
288 		DBA_ID_DONE; \
289 		RETURN_FALSE; \
290 	}
291 
292 #define DBA_ID_GET2   DBA_ID_PARS; DBA_GET2;   DBA_FETCH_RESOURCE_WITH_ID(info, id)
293 #define DBA_ID_GET2_3 DBA_ID_PARS; DBA_GET2_3; DBA_FETCH_RESOURCE_WITH_ID(info, id)
294 
295 #define DBA_ID_DONE												\
296 	if (key_free) efree(key_free)
297 /* a DBA handler must have specific routines */
298 
299 #define DBA_NAMED_HND(alias, name, flags) \
300 {\
301 	#alias, flags, dba_open_##name, dba_close_##name, dba_fetch_##name, dba_update_##name, \
302 	dba_exists_##name, dba_delete_##name, dba_firstkey_##name, dba_nextkey_##name, \
303 	dba_optimize_##name, dba_sync_##name, dba_info_##name \
304 },
305 
306 #define DBA_HND(name, flags) DBA_NAMED_HND(name, name, flags)
307 
308 /* check whether the user has write access */
309 #define DBA_WRITE_CHECK \
310 	if(info->mode != DBA_WRITER && info->mode != DBA_TRUNC && info->mode != DBA_CREAT) { \
311 		php_error_docref(NULL, E_WARNING, "You cannot perform a modification to a database without proper access"); \
312 		RETURN_FALSE; \
313 	}
314 
315 /* the same check, but with a call to DBA_ID_DONE before returning */
316 #define DBA_WRITE_CHECK_WITH_ID \
317 	if(info->mode != DBA_WRITER && info->mode != DBA_TRUNC && info->mode != DBA_CREAT) { \
318 		php_error_docref(NULL, E_WARNING, "You cannot perform a modification to a database without proper access"); \
319 		DBA_ID_DONE; \
320 		RETURN_FALSE; \
321 	}
322 
323 /* }}} */
324 
325 /* {{{ globals */
326 
327 static dba_handler handler[] = {
328 #if DBA_GDBM
329 	DBA_HND(gdbm, DBA_LOCK_EXT) /* Locking done in library if set */
330 #endif
331 #if DBA_DBM
332 	DBA_HND(dbm, DBA_LOCK_ALL) /* No lock in lib */
333 #endif
334 #if DBA_NDBM
335 	DBA_HND(ndbm, DBA_LOCK_ALL) /* Could be done in library: filemode = 0644 + S_ENFMT */
336 #endif
337 #if DBA_CDB
338 	DBA_HND(cdb, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
339 #endif
340 #if DBA_CDB_BUILTIN
341     DBA_NAMED_HND(cdb_make, cdb, DBA_STREAM_OPEN|DBA_LOCK_ALL) /* No lock in lib */
342 #endif
343 #if DBA_DB1
344 	DBA_HND(db1, DBA_LOCK_ALL) /* No lock in lib */
345 #endif
346 #if DBA_DB2
347 	DBA_HND(db2, DBA_LOCK_ALL) /* No lock in lib */
348 #endif
349 #if DBA_DB3
350 	DBA_HND(db3, DBA_LOCK_ALL) /* No lock in lib */
351 #endif
352 #if DBA_DB4
353 	DBA_HND(db4, DBA_LOCK_ALL) /* No lock in lib */
354 #endif
355 #if DBA_INIFILE
356 	DBA_HND(inifile, DBA_STREAM_OPEN|DBA_LOCK_ALL|DBA_CAST_AS_FD) /* No lock in lib */
357 #endif
358 #if DBA_FLATFILE
359 	DBA_HND(flatfile, DBA_STREAM_OPEN|DBA_LOCK_ALL|DBA_NO_APPEND) /* No lock in lib */
360 #endif
361 #if DBA_QDBM
362 	DBA_HND(qdbm, DBA_LOCK_EXT)
363 #endif
364 #if DBA_TCADB
365 	DBA_HND(tcadb, DBA_LOCK_ALL)
366 #endif
367 #if DBA_LMDB
368 	DBA_HND(lmdb, DBA_LOCK_EXT)
369 #endif
370 	{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
371 };
372 
373 #if DBA_FLATFILE
374 #define DBA_DEFAULT "flatfile"
375 #elif DBA_DB4
376 #define DBA_DEFAULT "db4"
377 #elif DBA_DB3
378 #define DBA_DEFAULT "db3"
379 #elif DBA_DB2
380 #define DBA_DEFAULT "db2"
381 #elif DBA_DB1
382 #define DBA_DEFAULT "db1"
383 #elif DBA_GDBM
384 #define DBA_DEFAULT "gdbm"
385 #elif DBA_NBBM
386 #define DBA_DEFAULT "ndbm"
387 #elif DBA_DBM
388 #define DBA_DEFAULT "dbm"
389 #elif DBA_QDBM
390 #define DBA_DEFAULT "qdbm"
391 #elif DBA_TCADB
392 #define DBA_DEFAULT "tcadb"
393 #elif DBA_LMDB
394 #define DBA_DEFAULT "lmdb"
395 #else
396 #define DBA_DEFAULT ""
397 #endif
398 /* cdb/cdb_make and ini are no option here */
399 
400 static int le_db;
401 static int le_pdb;
402 /* }}} */
403 
404 /* {{{ dba_fetch_resource
405 PHPAPI void dba_fetch_resource(dba_info **pinfo, zval **id)
406 {
407 	dba_info *info;
408 	DBA_ID_FETCH
409 	*pinfo = info;
410 }
411 */
412 /* }}} */
413 
414 /* {{{ dba_get_handler
415 PHPAPI dba_handler *dba_get_handler(const char* handler_name)
416 {
417 	dba_handler *hptr;
418 	for (hptr = handler; hptr->name && strcasecmp(hptr->name, handler_name); hptr++);
419 	return hptr;
420 }
421 */
422 /* }}} */
423 
424 /* {{{ dba_close
425  */
dba_close(dba_info * info)426 static void dba_close(dba_info *info)
427 {
428 	if (info->hnd) {
429 		info->hnd->close(info);
430 	}
431 	if (info->path) {
432 		pefree(info->path, info->flags&DBA_PERSISTENT);
433 	}
434 	if (info->fp && info->fp != info->lock.fp) {
435 		if (info->flags & DBA_PERSISTENT) {
436 			php_stream_pclose(info->fp);
437 		} else {
438 			php_stream_close(info->fp);
439 		}
440 	}
441 	if (info->lock.fp) {
442 		if (info->flags & DBA_PERSISTENT) {
443 			php_stream_pclose(info->lock.fp);
444 		} else {
445 			php_stream_close(info->lock.fp);
446 		}
447 	}
448 	if (info->lock.name) {
449 		pefree(info->lock.name, info->flags&DBA_PERSISTENT);
450 	}
451 	pefree(info, info->flags&DBA_PERSISTENT);
452 }
453 /* }}} */
454 
455 /* {{{ dba_close_rsrc
456  */
dba_close_rsrc(zend_resource * rsrc)457 static void dba_close_rsrc(zend_resource *rsrc)
458 {
459 	dba_info *info = (dba_info *)rsrc->ptr;
460 
461 	dba_close(info);
462 }
463 /* }}} */
464 
465 /* {{{ dba_close_pe_rsrc_deleter */
dba_close_pe_rsrc_deleter(zval * el,void * pDba)466 int dba_close_pe_rsrc_deleter(zval *el, void *pDba)
467 {
468 	if (Z_RES_P(el)->ptr == pDba) {
469 		if (Z_DELREF_P(el) == 0) {
470 			return ZEND_HASH_APPLY_REMOVE;
471 		} else {
472 			return ZEND_HASH_APPLY_KEEP | ZEND_HASH_APPLY_STOP;
473 		}
474 	} else {
475 		return ZEND_HASH_APPLY_KEEP;
476 	}
477 }
478 /* }}} */
479 
480 /* {{{ dba_close_pe_rsrc */
dba_close_pe_rsrc(zend_resource * rsrc)481 static void dba_close_pe_rsrc(zend_resource *rsrc)
482 {
483 	dba_info *info = (dba_info *)rsrc->ptr;
484 
485 	/* closes the resource by calling dba_close_rsrc() */
486 	zend_hash_apply_with_argument(&EG(persistent_list), dba_close_pe_rsrc_deleter, info);
487 }
488 /* }}} */
489 
490 /* {{{ PHP_INI
491  */
ZEND_INI_MH(OnUpdateDefaultHandler)492 ZEND_INI_MH(OnUpdateDefaultHandler)
493 {
494 	dba_handler *hptr;
495 
496 	if (!ZSTR_LEN(new_value)) {
497 		DBA_G(default_hptr) = NULL;
498 		return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
499 	}
500 
501 	for (hptr = handler; hptr->name && strcasecmp(hptr->name, ZSTR_VAL(new_value)); hptr++);
502 
503 	if (!hptr->name) {
504 		php_error_docref(NULL, E_WARNING, "No such handler: %s", ZSTR_VAL(new_value));
505 		return FAILURE;
506 	}
507 	DBA_G(default_hptr) = hptr;
508 	return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
509 }
510 
511 PHP_INI_BEGIN()
512     STD_PHP_INI_ENTRY("dba.default_handler", DBA_DEFAULT, PHP_INI_ALL, OnUpdateDefaultHandler, default_handler,    zend_dba_globals, dba_globals)
PHP_INI_END()513 PHP_INI_END()
514 /* }}} */
515 
516 /* {{{ PHP_GINIT_FUNCTION
517  */
518 static PHP_GINIT_FUNCTION(dba)
519 {
520 	dba_globals->default_handler = "";
521 	dba_globals->default_hptr    = NULL;
522 }
523 /* }}} */
524 
525 /* {{{ PHP_MINIT_FUNCTION
526  */
PHP_MINIT_FUNCTION(dba)527 PHP_MINIT_FUNCTION(dba)
528 {
529 	REGISTER_INI_ENTRIES();
530 	le_db = zend_register_list_destructors_ex(dba_close_rsrc, NULL, "dba", module_number);
531 	le_pdb = zend_register_list_destructors_ex(dba_close_pe_rsrc, dba_close_rsrc, "dba persistent", module_number);
532 	return SUCCESS;
533 }
534 /* }}} */
535 
536 /* {{{ PHP_MSHUTDOWN_FUNCTION
537  */
PHP_MSHUTDOWN_FUNCTION(dba)538 PHP_MSHUTDOWN_FUNCTION(dba)
539 {
540 	UNREGISTER_INI_ENTRIES();
541 	return SUCCESS;
542 }
543 /* }}} */
544 
545 #include "zend_smart_str.h"
546 
547 /* {{{ PHP_MINFO_FUNCTION
548  */
PHP_MINFO_FUNCTION(dba)549 PHP_MINFO_FUNCTION(dba)
550 {
551 	dba_handler *hptr;
552 	smart_str handlers = {0};
553 
554 	for(hptr = handler; hptr->name; hptr++) {
555 		smart_str_appends(&handlers, hptr->name);
556 		smart_str_appendc(&handlers, ' ');
557  	}
558 
559 	php_info_print_table_start();
560  	php_info_print_table_row(2, "DBA support", "enabled");
561 	if (handlers.s) {
562 		smart_str_0(&handlers);
563 		php_info_print_table_row(2, "Supported handlers", ZSTR_VAL(handlers.s));
564 		smart_str_free(&handlers);
565 	} else {
566 		php_info_print_table_row(2, "Supported handlers", "none");
567 	}
568 	php_info_print_table_end();
569 	DISPLAY_INI_ENTRIES();
570 }
571 /* }}} */
572 
573 /* {{{ php_dba_update
574  */
php_dba_update(INTERNAL_FUNCTION_PARAMETERS,int mode)575 static void php_dba_update(INTERNAL_FUNCTION_PARAMETERS, int mode)
576 {
577 	size_t val_len;
578 	zval *id;
579 	dba_info *info = NULL;
580 	int ac = ZEND_NUM_ARGS();
581 	zval *key;
582 	char *val;
583 	char *key_str, *key_free;
584 	size_t key_len;
585 
586 	if (zend_parse_parameters(ac, "zsr", &key, &val, &val_len, &id) == FAILURE) {
587 		return;
588 	}
589 
590 	if ((key_len = php_dba_make_key(key, &key_str, &key_free)) == 0) {
591 		RETURN_FALSE;
592 	}
593 
594 	DBA_FETCH_RESOURCE_WITH_ID(info, id);
595 
596 	DBA_WRITE_CHECK_WITH_ID;
597 
598 	if (info->hnd->update(info, key_str, key_len, val, val_len, mode) == SUCCESS) {
599 		DBA_ID_DONE;
600 		RETURN_TRUE;
601 	}
602 
603 	DBA_ID_DONE;
604 	RETURN_FALSE;
605 }
606 /* }}} */
607 
608 #define FREENOW if(args) {int i; for (i=0; i<ac; i++) { zval_ptr_dtor(&args[i]); } efree(args);} if(key) efree(key)
609 
610 /* {{{ php_find_dbm
611  */
php_dba_find(const char * path)612 dba_info *php_dba_find(const char* path)
613 {
614 	zend_resource *le;
615 	dba_info *info;
616 	zend_long numitems, i;
617 
618 	numitems = zend_hash_next_free_element(&EG(regular_list));
619 	for (i=1; i<numitems; i++) {
620 		if ((le = zend_hash_index_find_ptr(&EG(regular_list), i)) == NULL) {
621 			continue;
622 		}
623 		if (le->type == le_db || le->type == le_pdb) {
624 			info = (dba_info *)(le->ptr);
625 			if (!strcmp(info->path, path)) {
626 				return (dba_info *)(le->ptr);
627 			}
628 		}
629 	}
630 
631 	return NULL;
632 }
633 /* }}} */
634 
635 /* {{{ php_dba_open
636  */
php_dba_open(INTERNAL_FUNCTION_PARAMETERS,int persistent)637 static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, int persistent)
638 {
639 	zval *args = NULL;
640 	int ac = ZEND_NUM_ARGS();
641 	dba_mode_t modenr;
642 	dba_info *info, *other;
643 	dba_handler *hptr;
644 	char *key = NULL, *error = NULL;
645 	size_t keylen = 0;
646 	int i;
647 	int lock_mode, lock_flag, lock_dbf = 0;
648 	char *file_mode;
649 	char mode[4], *pmode, *lock_file_mode = NULL;
650 	int persistent_flag = persistent ? STREAM_OPEN_PERSISTENT : 0;
651 	zend_string *opened_path = NULL;
652 	char *lock_name;
653 #ifdef PHP_WIN32
654 	zend_bool restarted = 0;
655 	zend_bool need_creation = 0;
656 #endif
657 
658 	if (ac < 2) {
659 		WRONG_PARAM_COUNT;
660 	}
661 
662 	/* we pass additional args to the respective handler */
663 	args = safe_emalloc(ac, sizeof(zval), 0);
664 	if (zend_get_parameters_array_ex(ac, args) != SUCCESS) {
665 		efree(args);
666 		WRONG_PARAM_COUNT;
667 	}
668 
669 	/* we only take string arguments */
670 	for (i = 0; i < ac; i++) {
671 		ZVAL_STR(&args[i], zval_get_string(&args[i]));
672 		keylen += Z_STRLEN(args[i]);
673 	}
674 
675 	if (persistent) {
676 		zend_resource *le;
677 
678 		/* calculate hash */
679 		key = safe_emalloc(keylen, 1, 1);
680 		key[keylen] = '\0';
681 		keylen = 0;
682 
683 		for(i = 0; i < ac; i++) {
684 			memcpy(key+keylen, Z_STRVAL(args[i]), Z_STRLEN(args[i]));
685 			keylen += Z_STRLEN(args[i]);
686 		}
687 
688 		/* try to find if we already have this link in our persistent list */
689 		if ((le = zend_hash_str_find_ptr(&EG(persistent_list), key, keylen)) != NULL) {
690 			FREENOW;
691 
692 			if (le->type != le_pdb) {
693 				RETURN_FALSE;
694 			}
695 
696 			info = (dba_info *)le->ptr;
697 
698 			GC_REFCOUNT(le)++;
699 			RETURN_RES(zend_register_resource(info, le_pdb));
700 			return;
701 		}
702 	}
703 
704 	if (ac==2) {
705 		hptr = DBA_G(default_hptr);
706 		if (!hptr) {
707 			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No default handler selected");
708 			FREENOW;
709 			RETURN_FALSE;
710 		}
711 	} else {
712 		for (hptr = handler; hptr->name && strcasecmp(hptr->name, Z_STRVAL(args[2])); hptr++);
713 	}
714 
715 	if (!hptr->name) {
716 		php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No such handler: %s", Z_STRVAL(args[2]));
717 		FREENOW;
718 		RETURN_FALSE;
719 	}
720 
721 	/* Check mode: [rwnc][fl]?t?
722 	 * r: Read
723 	 * w: Write
724 	 * n: Create/Truncate
725 	 * c: Create
726 	 *
727 	 * d: force lock on database file
728 	 * l: force lock on lck file
729 	 * -: ignore locking
730 	 *
731 	 * t: test open database, warning if locked
732 	 */
733 	strlcpy(mode, Z_STRVAL(args[1]), sizeof(mode));
734 	pmode = &mode[0];
735 	if (pmode[0] && (pmode[1]=='d' || pmode[1]=='l' || pmode[1]=='-')) { /* force lock on db file or lck file or disable locking */
736 		switch (pmode[1]) {
737 		case 'd':
738 			lock_dbf = 1;
739 			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
740 				lock_flag = (hptr->flags & DBA_LOCK_ALL);
741 				break;
742 			}
743 			/* no break */
744 		case 'l':
745 			lock_flag = DBA_LOCK_ALL;
746 			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
747 				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_NOTICE, "Handler %s does locking internally", hptr->name);
748 			}
749 			break;
750 		default:
751 		case '-':
752 			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
753 				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Locking cannot be disabled for handler %s", hptr->name);
754 				FREENOW;
755 				RETURN_FALSE;
756 			}
757 			lock_flag = 0;
758 			break;
759 		}
760 	} else {
761 		lock_flag = (hptr->flags&DBA_LOCK_ALL);
762 		lock_dbf = 1;
763 	}
764 	switch (*pmode++) {
765 		case 'r':
766 			modenr = DBA_READER;
767 			lock_mode = (lock_flag & DBA_LOCK_READER) ? LOCK_SH : 0;
768 			file_mode = "r";
769 			break;
770 		case 'w':
771 			modenr = DBA_WRITER;
772 			lock_mode = (lock_flag & DBA_LOCK_WRITER) ? LOCK_EX : 0;
773 			file_mode = "r+b";
774 			break;
775 		case 'c': {
776 #ifdef PHP_WIN32
777 			if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) {
778 				php_stream_statbuf ssb;
779 				need_creation = (SUCCESS != php_stream_stat_path(Z_STRVAL(args[0]), &ssb));
780 			}
781 #endif
782 			modenr = DBA_CREAT;
783 			lock_mode = (lock_flag & DBA_LOCK_CREAT) ? LOCK_EX : 0;
784 			if (lock_mode) {
785 				if (lock_dbf) {
786 					/* the create/append check will be done on the lock
787 					 * when the lib opens the file it is already created
788 					 */
789 					file_mode = "r+b";       /* read & write, seek 0 */
790 #ifdef PHP_WIN32
791 					if (!need_creation) {
792 						lock_file_mode = "r+b";
793 					} else
794 #endif
795 					lock_file_mode = "a+b";  /* append */
796 				} else {
797 #ifdef PHP_WIN32
798 					if (!need_creation) {
799 						file_mode = "r+b";
800 					} else
801 #endif
802 					file_mode = "a+b";       /* append */
803 					lock_file_mode = "w+b";  /* create/truncate */
804 				}
805 			} else {
806 #ifdef PHP_WIN32
807 				if (!need_creation) {
808 					file_mode = "r+b";
809 				} else
810 #endif
811 				file_mode = "a+b";
812 			}
813 			/* In case of the 'a+b' append mode, the handler is responsible
814 			 * to handle any rewind problems (see flatfile handler).
815 			 */
816 			break;
817 		}
818 		case 'n':
819 			modenr = DBA_TRUNC;
820 			lock_mode = (lock_flag & DBA_LOCK_TRUNC) ? LOCK_EX : 0;
821 			file_mode = "w+b";
822 			break;
823 		default:
824 			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Illegal DBA mode");
825 			FREENOW;
826 			RETURN_FALSE;
827 	}
828 	if (!lock_file_mode) {
829 		lock_file_mode = file_mode;
830 	}
831 	if (*pmode=='d' || *pmode=='l' || *pmode=='-') {
832 		pmode++; /* done already - skip here */
833 	}
834 	if (*pmode=='t') {
835 		pmode++;
836 		if (!lock_flag) {
837 			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "You cannot combine modifiers - (no lock) and t (test lock)");
838 			FREENOW;
839 			RETURN_FALSE;
840 		}
841 		if (!lock_mode) {
842 			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
843 				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Handler %s uses its own locking which doesn't support mode modifier t (test lock)", hptr->name);
844 				FREENOW;
845 				RETURN_FALSE;
846 			} else {
847 				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Handler %s doesn't uses locking for this mode which makes modifier t (test lock) obsolete", hptr->name);
848 				FREENOW;
849 				RETURN_FALSE;
850 			}
851 		} else {
852 			lock_mode |= LOCK_NB; /* test =: non blocking */
853 		}
854 	}
855 	if (*pmode) {
856 		php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Illegal DBA mode");
857 		FREENOW;
858 		RETURN_FALSE;
859 	}
860 
861 	info = pemalloc(sizeof(dba_info), persistent);
862 	memset(info, 0, sizeof(dba_info));
863 	info->path = pestrdup(Z_STRVAL(args[0]), persistent);
864 	info->mode = modenr;
865 	info->argc = ac - 3;
866 	info->argv = args + 3;
867 	info->flags = (hptr->flags & ~DBA_LOCK_ALL) | (lock_flag & DBA_LOCK_ALL) | (persistent ? DBA_PERSISTENT : 0);
868 	info->lock.mode = lock_mode;
869 
870 	/* if any open call is a locking call:
871 	 * check if we already habe a locking call open that should block this call
872 	 * the problem is some systems would allow read during write
873 	 */
874 	if (hptr->flags & DBA_LOCK_ALL) {
875 		if ((other = php_dba_find(info->path)) != NULL) {
876 			if (   ( (lock_mode&LOCK_EX)        && (other->lock.mode&(LOCK_EX|LOCK_SH)) )
877 			    || ( (other->lock.mode&LOCK_EX) && (lock_mode&(LOCK_EX|LOCK_SH))        )
878 			   ) {
879 				error = "Unable to establish lock (database file already open)"; /* force failure exit */
880 			}
881 		}
882 	}
883 
884 #ifdef PHP_WIN32
885 restart:
886 #endif
887 	if (!error && lock_mode) {
888 		if (lock_dbf) {
889 			lock_name = Z_STRVAL(args[0]);
890 		} else {
891 			spprintf(&lock_name, 0, "%s.lck", info->path);
892 			if (!strcmp(file_mode, "r")) {
893 				/* when in read only mode try to use existing .lck file first */
894 				/* do not log errors for .lck file while in read ony mode on .lck file */
895 				lock_file_mode = "rb";
896 				info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, &opened_path);
897 			}
898 			if (!info->lock.fp) {
899 				/* when not in read mode or failed to open .lck file read only. now try again in create(write) mode and log errors */
900 				lock_file_mode = "a+b";
901 			} else {
902 				if (opened_path) {
903 					info->lock.name = pestrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path), persistent);
904 					zend_string_release(opened_path);
905 				}
906 			}
907 		}
908 		if (!info->lock.fp) {
909 			info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path);
910 			if (info->lock.fp) {
911 				if (lock_dbf) {
912 					/* replace the path info with the real path of the opened file */
913 					pefree(info->path, persistent);
914 					info->path = pestrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path), persistent);
915 				}
916 				/* now store the name of the lock */
917 				info->lock.name = pestrndup(ZSTR_VAL(opened_path), ZSTR_LEN(opened_path), persistent);
918 				zend_string_release(opened_path);
919 			}
920 		}
921 		if (!lock_dbf) {
922 			efree(lock_name);
923 		}
924 		if (!info->lock.fp) {
925 			dba_close(info);
926 			/* stream operation already wrote an error message */
927 			FREENOW;
928 			RETURN_FALSE;
929 		}
930 		if (!php_stream_supports_lock(info->lock.fp)) {
931 			error = "Stream does not support locking";
932 		}
933 		if (php_stream_lock(info->lock.fp, lock_mode)) {
934 			error = "Unable to establish lock"; /* force failure exit */
935 		}
936 	}
937 
938 	/* centralised open stream for builtin */
939 	if (!error && (hptr->flags&DBA_STREAM_OPEN)==DBA_STREAM_OPEN) {
940 		if (info->lock.fp && lock_dbf) {
941 			info->fp = info->lock.fp; /* use the same stream for locking and database access */
942 		} else {
943 			info->fp = php_stream_open_wrapper(info->path, file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL);
944 		}
945 		if (!info->fp) {
946 			dba_close(info);
947 			/* stream operation already wrote an error message */
948 			FREENOW;
949 			RETURN_FALSE;
950 		}
951 		if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) {
952 			/* Needed because some systems do not allow to write to the original
953 			 * file contents with O_APPEND being set.
954 			 */
955 			if (SUCCESS != php_stream_cast(info->fp, PHP_STREAM_AS_FD, (void*)&info->fd, 1)) {
956 				php_error_docref(NULL, E_WARNING, "Could not cast stream");
957 				dba_close(info);
958 				FREENOW;
959 				RETURN_FALSE;
960 #ifdef F_SETFL
961 			} else if (modenr == DBA_CREAT) {
962 				int flags = fcntl(info->fd, F_GETFL);
963 				fcntl(info->fd, F_SETFL, flags & ~O_APPEND);
964 #elif defined(PHP_WIN32)
965 			} else if (modenr == DBA_CREAT && need_creation && !restarted) {
966 				zend_bool close_both;
967 
968 				close_both = (info->fp != info->lock.fp);
969 				php_stream_close(info->lock.fp);
970 				if (close_both) {
971 					php_stream_close(info->fp);
972 				}
973 				info->fp = NULL;
974 				info->lock.fp = NULL;
975 				info->fd = -1;
976 
977 				pefree(info->lock.name, persistent);
978 
979 				lock_file_mode = "r+b";
980 
981 				restarted = 1;
982 				goto restart;
983 #endif
984 			}
985 		}
986 	}
987 
988 	if (error || hptr->open(info, &error) != SUCCESS) {
989 		dba_close(info);
990 		php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Driver initialization failed for handler: %s%s%s", hptr->name, error?": ":"", error?error:"");
991 		FREENOW;
992 		RETURN_FALSE;
993 	}
994 
995 	info->hnd = hptr;
996 	info->argc = 0;
997 	info->argv = NULL;
998 
999 	if (persistent) {
1000 		zval new_le;
1001 
1002 		ZVAL_NEW_PERSISTENT_RES(&new_le, -1, info, le_pdb);
1003 		if (zend_hash_str_update(&EG(persistent_list), key, keylen, &new_le) == NULL) {
1004 			dba_close(info);
1005 			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Could not register persistent resource");
1006 			FREENOW;
1007 			RETURN_FALSE;
1008 		}
1009 	}
1010 
1011 	RETVAL_RES(zend_register_resource(info, (persistent ? le_pdb : le_db)));
1012 	FREENOW;
1013 }
1014 /* }}} */
1015 #undef FREENOW
1016 
1017 /* {{{ proto resource dba_popen(string path, string mode [, string handlername, string ...])
1018    Opens path using the specified handler in mode persistently */
PHP_FUNCTION(dba_popen)1019 PHP_FUNCTION(dba_popen)
1020 {
1021 	php_dba_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1022 }
1023 /* }}} */
1024 
1025 /* {{{ proto resource dba_open(string path, string mode [, string handlername, string ...])
1026    Opens path using the specified handler in mode*/
PHP_FUNCTION(dba_open)1027 PHP_FUNCTION(dba_open)
1028 {
1029 	php_dba_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1030 }
1031 /* }}} */
1032 
1033 /* {{{ proto void dba_close(resource handle)
1034    Closes database */
PHP_FUNCTION(dba_close)1035 PHP_FUNCTION(dba_close)
1036 {
1037 	zval *id;
1038 	dba_info *info = NULL;
1039 
1040 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1041 		return;
1042 	}
1043 
1044 	DBA_FETCH_RESOURCE(info, id);
1045 
1046 	zend_list_close(Z_RES_P(id));
1047 }
1048 /* }}} */
1049 
1050 /* {{{ proto bool dba_exists(string key, resource handle)
1051    Checks, if the specified key exists */
PHP_FUNCTION(dba_exists)1052 PHP_FUNCTION(dba_exists)
1053 {
1054 	DBA_ID_GET2;
1055 
1056 	if(info->hnd->exists(info, key_str, key_len) == SUCCESS) {
1057 		DBA_ID_DONE;
1058 		RETURN_TRUE;
1059 	}
1060 	DBA_ID_DONE;
1061 	RETURN_FALSE;
1062 }
1063 /* }}} */
1064 
1065 /* {{{ proto string dba_fetch(string key, [int skip ,] resource handle)
1066    Fetches the data associated with key */
PHP_FUNCTION(dba_fetch)1067 PHP_FUNCTION(dba_fetch)
1068 {
1069 	char *val;
1070 	size_t len = 0;
1071 	DBA_ID_GET2_3;
1072 
1073 	if (ac==3) {
1074 		if (!strcmp(info->hnd->name, "cdb")) {
1075 			if (skip < 0) {
1076 				php_error_docref(NULL, E_NOTICE, "Handler %s accepts only skip values greater than or equal to zero, using skip=0", info->hnd->name);
1077 				skip = 0;
1078 			}
1079 		} else if (!strcmp(info->hnd->name, "inifile")) {
1080 			/* "-1" is compareable to 0 but allows a non restrictive
1081 			 * access which is fater. For example 'inifile' uses this
1082 			 * to allow faster access when the key was already found
1083 			 * using firstkey/nextkey. However explicitly setting the
1084 			 * value to 0 ensures the first value.
1085 			 */
1086 			if (skip < -1) {
1087 				php_error_docref(NULL, E_NOTICE, "Handler %s accepts only skip value -1 and greater, using skip=0", info->hnd->name);
1088 				skip = 0;
1089 			}
1090 		} else {
1091 			php_error_docref(NULL, E_NOTICE, "Handler %s does not support optional skip parameter, the value will be ignored", info->hnd->name);
1092 			skip = 0;
1093 		}
1094 	} else {
1095 		skip = 0;
1096 	}
1097 	if((val = info->hnd->fetch(info, key_str, key_len, skip, &len)) != NULL) {
1098 		DBA_ID_DONE;
1099 		RETVAL_STRINGL(val, len);
1100 		efree(val);
1101 		return;
1102 	}
1103 	DBA_ID_DONE;
1104 	RETURN_FALSE;
1105 }
1106 /* }}} */
1107 
1108 /* {{{ proto array|false dba_key_split(string key)
1109    Splits an inifile key into an array of the form array(0=>group,1=>value_name) but returns false if input is false or null */
PHP_FUNCTION(dba_key_split)1110 PHP_FUNCTION(dba_key_split)
1111 {
1112 	zval *zkey;
1113 	char *key, *name;
1114 	size_t key_len;
1115 
1116 	if (ZEND_NUM_ARGS() != 1) {
1117 		WRONG_PARAM_COUNT;
1118 	}
1119 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &zkey) == SUCCESS) {
1120 		if (Z_TYPE_P(zkey) == IS_NULL || (Z_TYPE_P(zkey) == IS_FALSE)) {
1121 			RETURN_BOOL(0);
1122 		}
1123 	}
1124 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &key, &key_len) == FAILURE) {
1125 		RETURN_BOOL(0);
1126 	}
1127 	array_init(return_value);
1128 	if (key[0] == '[' && (name = strchr(key, ']')) != NULL) {
1129 		add_next_index_stringl(return_value, key+1, name - (key + 1));
1130 		add_next_index_stringl(return_value, name+1, key_len - (name - key + 1));
1131 	} else {
1132 		add_next_index_stringl(return_value, "", 0);
1133 		add_next_index_stringl(return_value, key, key_len);
1134 	}
1135 }
1136 /* }}} */
1137 
1138 /* {{{ proto string dba_firstkey(resource handle)
1139    Resets the internal key pointer and returns the first key */
PHP_FUNCTION(dba_firstkey)1140 PHP_FUNCTION(dba_firstkey)
1141 {
1142 	char *fkey;
1143 	size_t len;
1144 	zval *id;
1145 	dba_info *info = NULL;
1146 
1147 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1148 		return;
1149 	}
1150 
1151 	DBA_FETCH_RESOURCE(info, id);
1152 
1153 	fkey = info->hnd->firstkey(info, &len);
1154 
1155 	if (fkey) {
1156 		RETVAL_STRINGL(fkey, len);
1157 		efree(fkey);
1158 		return;
1159 	}
1160 
1161 	RETURN_FALSE;
1162 }
1163 /* }}} */
1164 
1165 /* {{{ proto string dba_nextkey(resource handle)
1166    Returns the next key */
PHP_FUNCTION(dba_nextkey)1167 PHP_FUNCTION(dba_nextkey)
1168 {
1169 	char *nkey;
1170 	size_t len;
1171 	zval *id;
1172 	dba_info *info = NULL;
1173 
1174 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1175 		return;
1176 	}
1177 
1178 	DBA_FETCH_RESOURCE(info, id);
1179 
1180 	nkey = info->hnd->nextkey(info, &len);
1181 
1182 	if (nkey) {
1183 		RETVAL_STRINGL(nkey, len);
1184 		efree(nkey);
1185 		return;
1186 	}
1187 
1188 	RETURN_FALSE;
1189 }
1190 /* }}} */
1191 
1192 /* {{{ proto bool dba_delete(string key, resource handle)
1193    Deletes the entry associated with key
1194    If inifile: remove all other key lines */
PHP_FUNCTION(dba_delete)1195 PHP_FUNCTION(dba_delete)
1196 {
1197 	DBA_ID_GET2;
1198 
1199 	DBA_WRITE_CHECK_WITH_ID;
1200 
1201 	if(info->hnd->delete(info, key_str, key_len) == SUCCESS)
1202 	{
1203 		DBA_ID_DONE;
1204 		RETURN_TRUE;
1205 	}
1206 	DBA_ID_DONE;
1207 	RETURN_FALSE;
1208 }
1209 /* }}} */
1210 
1211 /* {{{ proto bool dba_insert(string key, string value, resource handle)
1212    If not inifile: Insert value as key, return false, if key exists already
1213    If inifile: Add vakue as key (next instance of key) */
PHP_FUNCTION(dba_insert)1214 PHP_FUNCTION(dba_insert)
1215 {
1216 	php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1217 }
1218 /* }}} */
1219 
1220 /* {{{ proto bool dba_replace(string key, string value, resource handle)
1221    Inserts value as key, replaces key, if key exists already
1222    If inifile: remove all other key lines */
PHP_FUNCTION(dba_replace)1223 PHP_FUNCTION(dba_replace)
1224 {
1225 	php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1226 }
1227 /* }}} */
1228 
1229 /* {{{ proto bool dba_optimize(resource handle)
1230    Optimizes (e.g. clean up, vacuum) database */
PHP_FUNCTION(dba_optimize)1231 PHP_FUNCTION(dba_optimize)
1232 {
1233 	zval *id;
1234 	dba_info *info = NULL;
1235 
1236 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1237 		return;
1238 	}
1239 
1240 	DBA_FETCH_RESOURCE(info, id);
1241 
1242 	DBA_WRITE_CHECK;
1243 
1244 	if (info->hnd->optimize(info) == SUCCESS) {
1245 		RETURN_TRUE;
1246 	}
1247 
1248 	RETURN_FALSE;
1249 }
1250 /* }}} */
1251 
1252 /* {{{ proto bool dba_sync(resource handle)
1253    Synchronizes database */
PHP_FUNCTION(dba_sync)1254 PHP_FUNCTION(dba_sync)
1255 {
1256 	zval *id;
1257 	dba_info *info = NULL;
1258 
1259 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) {
1260 		return;
1261 	}
1262 
1263 	DBA_FETCH_RESOURCE(info, id);
1264 
1265 	if (info->hnd->sync(info) == SUCCESS) {
1266 		RETURN_TRUE;
1267 	}
1268 
1269 	RETURN_FALSE;
1270 }
1271 /* }}} */
1272 
1273 /* {{{ proto array dba_handlers([bool full_info])
1274    List configured database handlers */
PHP_FUNCTION(dba_handlers)1275 PHP_FUNCTION(dba_handlers)
1276 {
1277 	dba_handler *hptr;
1278 	zend_bool full_info = 0;
1279 
1280 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &full_info) == FAILURE) {
1281 		RETURN_FALSE;
1282 	}
1283 
1284 	array_init(return_value);
1285 
1286 	for(hptr = handler; hptr->name; hptr++) {
1287 		if (full_info) {
1288 			// TODO: avoid reallocation ???
1289 			char *str = hptr->info(hptr, NULL);
1290 			add_assoc_string(return_value, hptr->name, str);
1291 			efree(str);
1292 		} else {
1293 			add_next_index_string(return_value, hptr->name);
1294 		}
1295  	}
1296 }
1297 /* }}} */
1298 
1299 /* {{{ proto array dba_list()
1300    List opened databases */
PHP_FUNCTION(dba_list)1301 PHP_FUNCTION(dba_list)
1302 {
1303 	zend_ulong numitems, i;
1304 	zend_resource *le;
1305 	dba_info *info;
1306 
1307 	if (zend_parse_parameters_none() == FAILURE) {
1308 		RETURN_FALSE;
1309 	}
1310 
1311 	array_init(return_value);
1312 
1313 	numitems = zend_hash_next_free_element(&EG(regular_list));
1314 	for (i=1; i<numitems; i++) {
1315 		if ((le = zend_hash_index_find_ptr(&EG(regular_list), i)) == NULL) {
1316 			continue;
1317 		}
1318 		if (le->type == le_db || le->type == le_pdb) {
1319 			info = (dba_info *)(le->ptr);
1320 			add_index_string(return_value, i, info->path);
1321 		}
1322 	}
1323 }
1324 /* }}} */
1325 
1326 #endif /* HAVE_DBA */
1327 
1328 /*
1329  * Local variables:
1330  * tab-width: 4
1331  * c-basic-offset: 4
1332  * End:
1333  * vim600: sw=4 ts=4 fdm=marker
1334  * vim<600: sw=4 ts=4
1335  */
1336