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