📄 dba.c
字号:
char *file_mode; char mode[4], *pmode, *lock_file_mode = NULL; int persistent_flag = persistent ? STREAM_OPEN_PERSISTENT : 0; if(ac < 2) { WRONG_PARAM_COUNT; } /* we pass additional args to the respective handler */ args = safe_emalloc(ac, sizeof(zval *), 0); if (zend_get_parameters_array_ex(ac, args) != SUCCESS) { FREENOW; WRONG_PARAM_COUNT; } /* we only take string arguments */ for (i = 0; i < ac; i++) { convert_to_string_ex(args[i]); keylen += Z_STRLEN_PP(args[i]); } if (persistent) { list_entry *le; /* calculate hash */ key = safe_emalloc(keylen, 1, 1); key[keylen] = '\0'; keylen = 0; for(i = 0; i < ac; i++) { memcpy(key+keylen, Z_STRVAL_PP(args[i]), Z_STRLEN_PP(args[i])); keylen += Z_STRLEN_PP(args[i]); } /* try to find if we already have this link in our persistent list */ if (zend_hash_find(&EG(persistent_list), key, keylen+1, (void **) &le) == SUCCESS) { FREENOW; if (Z_TYPE_P(le) != le_pdb) { RETURN_FALSE; } info = (dba_info *)le->ptr; ZEND_REGISTER_RESOURCE(return_value, info, le_pdb); return; } } if (ac==2) { hptr = DBA_G(default_hptr); if (!hptr) { php_error_docref2(NULL TSRMLS_CC, Z_STRVAL_PP(args[0]), Z_STRVAL_PP(args[1]), E_WARNING, "No default handler selected"); FREENOW; RETURN_FALSE; } } else { for (hptr = handler; hptr->name && strcasecmp(hptr->name, Z_STRVAL_PP(args[2])); hptr++); } if (!hptr->name) { 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])); FREENOW; RETURN_FALSE; } /* Check mode: [rwnc][fl]?t? * r: Read * w: Write * n: Create/Truncate * c: Create * * d: force lock on database file * l: force lock on lck file * -: ignore locking * * t: test open database, warning if locked */ strlcpy(mode, Z_STRVAL_PP(args[1]), sizeof(mode)); pmode = &mode[0]; if (pmode[0] && (pmode[1]=='d' || pmode[1]=='l' || pmode[1]=='-')) { /* force lock on db file or lck file or disable locking */ switch (pmode[1]) { case 'd': lock_dbf = 1; if ((hptr->flags & DBA_LOCK_ALL) == 0) { lock_flag = (hptr->flags & DBA_LOCK_ALL); break; } /* no break */ case 'l': lock_flag = DBA_LOCK_ALL; if ((hptr->flags & DBA_LOCK_ALL) == 0) { 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); } break; default: case '-': if ((hptr->flags & DBA_LOCK_ALL) == 0) { 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); FREENOW; RETURN_FALSE; } lock_flag = 0; break; } } else { lock_flag = (hptr->flags&DBA_LOCK_ALL); lock_dbf = 1; } switch (*pmode++) { case 'r': modenr = DBA_READER; lock_mode = (lock_flag & DBA_LOCK_READER) ? LOCK_SH : 0; file_mode = "r"; break; case 'w': modenr = DBA_WRITER; lock_mode = (lock_flag & DBA_LOCK_WRITER) ? LOCK_EX : 0; file_mode = "r+b"; break; case 'c': modenr = DBA_CREAT; lock_mode = (lock_flag & DBA_LOCK_CREAT) ? LOCK_EX : 0; if (lock_mode) { if (lock_dbf) { /* the create/append check will be done on the lock * when the lib opens the file it is already created */ file_mode = "r+b"; /* read & write, seek 0 */ lock_file_mode = "a+b"; /* append */ } else { file_mode = "a+b"; /* append */ lock_file_mode = "w+b"; /* create/truncate */ } } else { file_mode = "a+b"; } /* In case of the 'a+b' append mode, the handler is responsible * to handle any rewind problems (see flatfile handler). */ break; case 'n': modenr = DBA_TRUNC; lock_mode = (lock_flag & DBA_LOCK_TRUNC) ? LOCK_EX : 0; file_mode = "w+b"; break; default: php_error_docref2(NULL TSRMLS_CC, Z_STRVAL_PP(args[0]), Z_STRVAL_PP(args[1]), E_WARNING, "Illegal DBA mode"); FREENOW; RETURN_FALSE; } if (!lock_file_mode) { lock_file_mode = file_mode; } if (*pmode=='d' || *pmode=='l' || *pmode=='-') { pmode++; /* done already - skip here */ } if (*pmode=='t') { pmode++; if (!lock_flag) { 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)"); FREENOW; RETURN_FALSE; } if (!lock_mode) { if ((hptr->flags & DBA_LOCK_ALL) == 0) { 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); FREENOW; RETURN_FALSE; } else { 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); FREENOW; RETURN_FALSE; } } else { lock_mode |= LOCK_NB; /* test =: non blocking */ } } if (*pmode) { php_error_docref2(NULL TSRMLS_CC, Z_STRVAL_PP(args[0]), Z_STRVAL_PP(args[1]), E_WARNING, "Illegal DBA mode"); FREENOW; RETURN_FALSE; } info = pemalloc(sizeof(dba_info), persistent); memset(info, 0, sizeof(dba_info)); info->path = pestrdup(Z_STRVAL_PP(args[0]), persistent); info->mode = modenr; info->argc = ac - 3; info->argv = args + 3; info->flags = (hptr->flags & ~DBA_LOCK_ALL) | (lock_flag & DBA_LOCK_ALL) | (persistent ? DBA_PERSISTENT : 0); info->lock.mode = lock_mode; /* if any open call is a locking call: * check if we already habe a locking call open that should block this call * the problem is some systems would allow read during write */ if (hptr->flags & DBA_LOCK_ALL) { if ((other = php_dba_find(info->path TSRMLS_CC)) != NULL) { if ( ( (lock_mode&LOCK_EX) && (other->lock.mode&(LOCK_EX|LOCK_SH)) ) || ( (other->lock.mode&LOCK_EX) && (lock_mode&(LOCK_EX|LOCK_SH)) ) ) { error = "Unable to establish lock (database file already open)"; /* force failure exit */ } } } if (!error && lock_mode) { if (lock_dbf) { info->lock.name = pestrdup(info->path, persistent); } else { spprintf(&info->lock.name, 0, "%s.lck", info->path); if (!strcmp(file_mode, "r")) { /* when in read only mode try to use existing .lck file first */ /* do not log errors for .lck file while in read ony mode on .lck file */ lock_file_mode = "rb"; info->lock.fp = php_stream_open_wrapper(info->lock.name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|ENFORCE_SAFE_MODE|persistent_flag, NULL); } if (!info->lock.fp) { /* when not in read mode or failed to open .lck file read only. now try again in create(write) mode and log errors */ lock_file_mode = "a+b"; } } if (!info->lock.fp) { info->lock.fp = php_stream_open_wrapper(info->lock.name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE|persistent_flag, NULL); } if (!info->lock.fp) { dba_close(info TSRMLS_CC); /* stream operation already wrote an error message */ FREENOW; RETURN_FALSE; } if (php_stream_cast(info->lock.fp, PHP_STREAM_AS_FD, (void*)&info->lock.fd, 1) == FAILURE) { dba_close(info TSRMLS_CC); /* stream operation already wrote an error message */ FREENOW; RETURN_FALSE; } if (php_flock(info->lock.fd, lock_mode)) { error = "Unable to establish lock"; /* force failure exit */ } } /* centralised open stream for builtin */ if (!error && (hptr->flags&DBA_STREAM_OPEN)==DBA_STREAM_OPEN) { if (info->lock.fp && lock_dbf) { info->fp = info->lock.fp; /* use the same stream for locking and database access */ } else { info->fp = php_stream_open_wrapper(info->path, file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE|persistent_flag, NULL); } if (!info->fp) { dba_close(info TSRMLS_CC); /* stream operation already wrote an error message */ FREENOW; RETURN_FALSE; } } if (error || hptr->open(info, &error TSRMLS_CC) != SUCCESS) { dba_close(info TSRMLS_CC); 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:""); FREENOW; RETURN_FALSE; } info->hnd = hptr; info->argc = 0; info->argv = NULL; if (persistent) { list_entry new_le; Z_TYPE(new_le) = le_pdb; new_le.ptr = info; if (zend_hash_update(&EG(persistent_list), key, keylen+1, &new_le, sizeof(list_entry), NULL) == FAILURE) { dba_close(info TSRMLS_CC); php_error_docref2(NULL TSRMLS_CC, Z_STRVAL_PP(args[0]), Z_STRVAL_PP(args[1]), E_WARNING, "Could not register persistent resource"); FREENOW; RETURN_FALSE; } } ZEND_REGISTER_RESOURCE(return_value, info, (persistent ? le_pdb : le_db)); FREENOW;}/* }}} */#undef FREENOW/* {{{ proto resource dba_popen(string path, string mode [, string handlername, string ...]) Opens path using the specified handler in mode persistently */PHP_FUNCTION(dba_popen){ php_dba_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);}/* }}} *//* {{{ proto resource dba_open(string path, string mode [, string handlername, string ...]) Opens path using the specified handler in mode*/PHP_FUNCTION(dba_open){ php_dba_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);}/* }}} *//* {{{ proto void dba_close(resource handle) Closes database */PHP_FUNCTION(dba_close){ DBA_ID_GET1; zend_list_delete(Z_RESVAL_PP(id));}/* }}} *//* {{{ proto bool dba_exists(string key, resource handle) Checks, if the specified key exists */PHP_FUNCTION(dba_exists){ DBA_ID_GET2; if(info->hnd->exists(info, key_str, key_len TSRMLS_CC) == SUCCESS) { DBA_ID_DONE; RETURN_TRUE; } DBA_ID_DONE; RETURN_FALSE;}/* }}} *//* {{{ proto string dba_fetch(string key, [int skip ,] resource handle) Fetches the data associated with key */PHP_FUNCTION(dba_fetch){ char *val; int len = 0; DBA_ID_GET2_3; if (ac==3) { if (!strcmp(info->hnd->name, "cdb")) { if (skip < 0) { 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); skip = 0; } } else if (!strcmp(info->hnd->name, "inifile")) { /* "-1" is compareable to 0 but allows a non restrictive * access which is fater. For example 'inifile' uses this * to allow faster access when the key was already found * using firstkey/nextkey. However explicitly setting the * value to 0 ensures the first value. */ if (skip < -1) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s accepts only skip value -1 and greater, using skip=0", info->hnd->name); skip = 0; } } else { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Handler %s does not support optional skip parameter, the value will be ignored", info->hnd->name); skip = 0; } } else { skip = 0; } if((val = info->hnd->fetch(info, key_str, key_len, skip, &len TSRMLS_CC)) != NULL) { if (val && PG(magic_quotes_runtime)) { val = php_addslashes(val, len, &len, 1 TSRMLS_CC); } DBA_ID_DONE; RETURN_STRINGL(val, len, 0); } DBA_ID_DONE; RETURN_FALSE;}/* }}} *//* {{{ proto string dba_firstkey(resource handle) Resets the internal key pointer and returns the first key */PHP_FUNCTION(dba_firstkey){ char *fkey; int len; DBA_ID_GET1; fkey = info->hnd->firstkey(info, &len TSRMLS_CC); if(fkey) RETURN_STRINGL(fkey, len, 0); RETURN_FALSE;}/* }}} *//* {{{ proto string dba_nextkey(resource handle) Returns the next key */PHP_FUNCTION(dba_nextkey){ char *nkey; int len; DBA_ID_GET1; nkey = info->hnd->nextkey(info, &len TSRMLS_CC); if(nkey) RETURN_STRINGL(nkey, len, 0); RETURN_FALSE;}/* }}} *//* {{{ proto bool dba_delete(string key, resource handle) Deletes the entry associated with key If inifile: remove all other key lines */PHP_FUNCTION(dba_delete){ DBA_ID_GET2; DBA_WRITE_CHECK; if(info->hnd->delete(info, key_str, key_len TSRMLS_CC) == SUCCESS) { DBA_ID_DONE; RETURN_TRUE; } DBA_ID_DONE; RETURN_FALSE;}/* }}} *//* {{{ proto bool dba_insert(string key, string value, resource handle) If not inifile: Insert value as key, return false, if key exists already If inifile: Add vakue as key (next instance of key) */PHP_FUNCTION(dba_insert){ php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);}/* }}} *//* {{{ proto bool dba_replace(string key, string value, resource handle) Inserts value as key, replaces key, if key exists already If inifile: remove all other key lines */PHP_FUNCTION(dba_replace){ php_dba_update(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);}/* }}} *//* {{{ proto bool dba_optimize(resource handle) Optimizes (e.g. clean up, vacuum) database */PHP_FUNCTION(dba_optimize){ DBA_ID_GET1; DBA_WRITE_CHECK; if(info->hnd->optimize(info TSRMLS_CC) == SUCCESS) { RETURN_TRUE; } RETURN_FALSE;}/* }}} *//* {{{ proto bool dba_sync(resource handle) Synchronizes database */PHP_FUNCTION(dba_sync){ DBA_ID_GET1; if(info->hnd->sync(info TSRMLS_CC) == SUCCESS) { RETURN_TRUE; } RETURN_FALSE;}/* }}} *//* {{{ proto array dba_handlers([bool full_info]) List configured database handlers */PHP_FUNCTION(dba_handlers){ dba_handler *hptr; zend_bool full_info = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_info) == FAILURE) { ZEND_WRONG_PARAM_COUNT(); RETURN_FALSE; } array_init(return_value); for(hptr = handler; hptr->name; hptr++) { if (full_info) { add_assoc_string(return_value, hptr->name, hptr->info(hptr, NULL TSRMLS_CC), 0); } else { add_next_index_string(return_value, hptr->name, 1); } }}/* }}} *//* {{{ proto array dba_list() List opened databases */PHP_FUNCTION(dba_list){ ulong numitems, i; zend_rsrc_list_entry *le; dba_info *info; if (ZEND_NUM_ARGS()!=0) { ZEND_WRONG_PARAM_COUNT(); RETURN_FALSE; } array_init(return_value); numitems = zend_hash_next_free_element(&EG(regular_list)); for (i=1; i<numitems; i++) { if (zend_hash_index_find(&EG(regular_list), i, (void **) &le)==FAILURE) { continue; } if (Z_TYPE_P(le) == le_db || Z_TYPE_P(le) == le_pdb) { info = (dba_info *)(le->ptr); add_index_string(return_value, i, info->path, 1); } }}/* }}} */#endif /* HAVE_DBA *//* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -