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