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