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