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