/* {{{ php_dba_open */ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, int persistent) { zval *args = NULL; int ac = ZEND_NUM_ARGS(); dba_mode_t modenr; dba_info *info, *other; dba_handler *hptr; char *key = NULL, *error = NULL; int keylen = 0; int i; int lock_mode, lock_flag, lock_dbf = 0; char *file_mode; char mode[4], *pmode, *lock_file_mode = NULL; int persistent_flag = persistent ? STREAM_OPEN_PERSISTENT : 0; zend_string *opened_path = NULL; char *lock_name; 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) { efree(args); WRONG_PARAM_COUNT; } /* we only take string arguments */ for (i = 0; i < ac; i++) { if (Z_TYPE(args[i]) != IS_STRING) { convert_to_string_ex(&args[i]); } else if (Z_REFCOUNTED(args[i])) { Z_ADDREF(args[i]); } keylen += Z_STRLEN(args[i]); } if (persistent) { zend_resource *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(args[i]), Z_STRLEN(args[i])); keylen += Z_STRLEN(args[i]); } /* try to find if we already have this link in our persistent list */ if ((le = zend_hash_str_find_ptr(&EG(persistent_list), key, keylen)) != NULL) { FREENOW; if (le->type != le_pdb) { RETURN_FALSE; } info = (dba_info *)le->ptr; GC_REFCOUNT(le)++; RETURN_RES(le); return; } } if (ac==2) { hptr = DBA_G(default_hptr); if (!hptr) { php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No default handler selected"); FREENOW; RETURN_FALSE; } } else { for (hptr = handler; hptr->name && strcasecmp(hptr->name, Z_STRVAL(args[2])); hptr++); } if (!hptr->name) { php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No such handler: %s", Z_STRVAL(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(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, Z_STRVAL(args[0]), Z_STRVAL(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, Z_STRVAL(args[0]), Z_STRVAL(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, Z_STRVAL(args[0]), Z_STRVAL(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, Z_STRVAL(args[0]), Z_STRVAL(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, 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); FREENOW; RETURN_FALSE; } else { 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); FREENOW; RETURN_FALSE; } } else { lock_mode |= LOCK_NB; /* test =: non blocking */ } } if (*pmode) { php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(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(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)) != 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) { lock_name = Z_STRVAL(args[0]); } else { spprintf(&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(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, &opened_path); } 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"; } else { if (opened_path) { info->lock.name = pestrndup(opened_path->val, opened_path->len, persistent); zend_string_release(opened_path); } } } if (!info->lock.fp) { info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path); if (info->lock.fp) { if (lock_dbf) { /* replace the path info with the real path of the opened file */ pefree(info->path, persistent); info->path = pestrndup(opened_path->val, opened_path->len, persistent); } /* now store the name of the lock */ info->lock.name = pestrndup(opened_path->val, opened_path->len, persistent); zend_string_release(opened_path); } } if (!lock_dbf) { efree(lock_name); } if (!info->lock.fp) { dba_close(info); /* stream operation already wrote an error message */ FREENOW; RETURN_FALSE; } if (!php_stream_supports_lock(info->lock.fp)) { error = "Stream does not support locking"; } if (php_stream_lock(info->lock.fp, 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|persistent_flag, NULL); } if (!info->fp) { dba_close(info); /* stream operation already wrote an error message */ FREENOW; RETURN_FALSE; } if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) { /* Needed because some systems do not allow to write to the original * file contents with O_APPEND being set. */ if (SUCCESS != php_stream_cast(info->fp, PHP_STREAM_AS_FD, (void*)&info->fd, 1)) { php_error_docref(NULL, E_WARNING, "Could not cast stream"); dba_close(info); FREENOW; RETURN_FALSE; #ifdef F_SETFL } else if (modenr == DBA_CREAT) { int flags = fcntl(info->fd, F_SETFL); fcntl(info->fd, F_SETFL, flags & ~O_APPEND); #endif } } } if (error || hptr->open(info, &error) != SUCCESS) { dba_close(info); 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:""); FREENOW; RETURN_FALSE; } info->hnd = hptr; info->argc = 0; info->argv = NULL; if (persistent) { zend_resource new_le; new_le.type = le_pdb; new_le.ptr = info; if (zend_hash_str_update_mem(&EG(persistent_list), key, keylen, &new_le, sizeof(zend_resource)) == NULL) { dba_close(info); php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Could not register persistent resource"); FREENOW; RETURN_FALSE; } } RETVAL_RES(zend_register_resource(info, (persistent ? le_pdb : le_db))); FREENOW; }
static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, int persistent) { pval ***args = (pval ***) NULL; int ac = ZEND_NUM_ARGS(); dba_mode_t modenr; dba_info *info; dba_handler *hptr; char *key = NULL; int keylen = 0; int listid; int i; if(ac < 3) { WRONG_PARAM_COUNT; } /* we pass additional args to the respective handler */ args = emalloc(ac * sizeof(pval *)); 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) { /* calculate hash */ key = emalloc(keylen); 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]); } if(zend_hash_find(&ht_keys, key, keylen, (void **) &info) == SUCCESS) { FREENOW; RETURN_LONG(zend_list_insert(info, GLOBAL(le_pdb))); } } for(hptr = handler; hptr->name && strcasecmp(hptr->name, (*args[2])->value.str.val); hptr++); if(!hptr->name) { php_error(E_WARNING, "no such handler: %s", (*args[2])->value.str.val); FREENOW; RETURN_FALSE; } switch((*args[1])->value.str.val[0]) { case 'c': modenr = DBA_CREAT; break; case 'w': modenr = DBA_WRITER; break; case 'r': modenr = DBA_READER; break; case 'n': modenr = DBA_TRUNC; break; default: php_error(E_WARNING,"illegal DBA mode: %s",(*args[1])->value.str.val); FREENOW; RETURN_FALSE; } info = malloc(sizeof(*info)); memset(info, 0, sizeof(info)); info->path = strdup((*args[0])->value.str.val); info->mode = modenr; info->argc = ac - 3; info->argv = args + 3; info->hnd = NULL; if(hptr->open(info) != SUCCESS) { dba_close(info); php_error(E_WARNING, "driver initialization failed"); FREENOW; RETURN_FALSE; } info->hnd = hptr; info->argc = 0; info->argv = NULL; listid = zend_list_insert(info, persistent?GLOBAL(le_pdb):GLOBAL(le_db)); if(persistent) { zend_hash_update(&ht_keys, key, keylen, info, sizeof(*info), NULL); } FREENOW; RETURN_LONG(listid); }
/* {{{ dba_close_rsrc */ static void dba_close_rsrc(zend_resource *rsrc) { dba_info *info = (dba_info *)rsrc->ptr; dba_close(info); }
static void dba_close_rsrc(zend_rsrc_list_entry *rsrc) { dba_info *info = (dba_info *)rsrc->ptr; dba_close(info); }