Annotation of embedaddon/php/ext/dba/dba.c, revision 1.1.1.5

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>