/* {{{ inifile_copy_to */ static int inifile_copy_to(inifile *dba, size_t pos_start, size_t pos_end, inifile **ini_copy) { php_stream *fp; if (pos_start == pos_end) { *ini_copy = NULL; return SUCCESS; } if ((fp = php_stream_temp_create(0, 64 * 1024)) == NULL) { php_error_docref(NULL, E_WARNING, "Could not create temporary stream"); *ini_copy = NULL; return FAILURE; } if ((*ini_copy = inifile_alloc(fp, 1, 0)) == NULL) { /* writes error */ return FAILURE; } php_stream_seek(dba->fp, pos_start, SEEK_SET); if (SUCCESS != php_stream_copy_to_stream_ex(dba->fp, fp, pos_end - pos_start, NULL)) { php_error_docref(NULL, E_WARNING, "Could not copy group [%zu - %zu] to temporary stream", pos_start, pos_end); return FAILURE; } return SUCCESS; }
/* {{{ inifile_filter * copy from to dba while ignoring key name (group must equal) */ static int inifile_filter(inifile *dba, inifile *from, const key_type *key, zend_bool *found) { size_t pos_start = 0, pos_next = 0, pos_curr; int ret = SUCCESS; line_type ln = {{NULL,NULL},{NULL}}; php_stream_seek(from->fp, 0, SEEK_SET); php_stream_seek(dba->fp, 0, SEEK_END); while(inifile_read(from, &ln)) { switch(inifile_key_cmp(&ln.key, key)) { case 0: if (found) { *found = (zend_bool) 1; } pos_curr = php_stream_tell(from->fp); if (pos_start != pos_next) { php_stream_seek(from->fp, pos_start, SEEK_SET); if (SUCCESS != php_stream_copy_to_stream_ex(from->fp, dba->fp, pos_next - pos_start, NULL)) { php_error_docref(NULL, E_WARNING, "Could not copy [%zu - %zu] from temporary stream", pos_next, pos_start); ret = FAILURE; } php_stream_seek(from->fp, pos_curr, SEEK_SET); } pos_next = pos_start = pos_curr; break; case 1: pos_next = php_stream_tell(from->fp); break; case 2: /* the function is meant to process only entries from same group */ assert(0); break; } } if (pos_start != pos_next) { php_stream_seek(from->fp, pos_start, SEEK_SET); if (SUCCESS != php_stream_copy_to_stream_ex(from->fp, dba->fp, pos_next - pos_start, NULL)) { php_error_docref(NULL, E_WARNING, "Could not copy [%zu - %zu] from temporary stream", pos_next, pos_start); ret = FAILURE; } } inifile_line_free(&ln); return ret; }
/* {{{ php_stream_cast */ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err) { int flags = castas & PHP_STREAM_CAST_MASK; castas &= ~PHP_STREAM_CAST_MASK; /* synchronize our buffer (if possible) */ if (ret && castas != PHP_STREAM_AS_FD_FOR_SELECT) { php_stream_flush(stream); if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { zend_off_t dummy; stream->ops->seek(stream, stream->position, SEEK_SET, &dummy); stream->readpos = stream->writepos = 0; } } /* filtered streams can only be cast as stdio, and only when fopencookie is present */ if (castas == PHP_STREAM_AS_STDIO) { if (stream->stdiocast) { if (ret) { *(FILE**)ret = stream->stdiocast; } goto exit_success; } /* if the stream is a stdio stream let's give it a chance to respond * first, to avoid doubling up the layers of stdio with an fopencookie */ if (php_stream_is(stream, PHP_STREAM_IS_STDIO) && stream->ops->cast && !php_stream_is_filtered(stream) && stream->ops->cast(stream, castas, ret) == SUCCESS ) { goto exit_success; } #if HAVE_FOPENCOOKIE /* if just checking, say yes we can be a FILE*, but don't actually create it yet */ if (ret == NULL) { goto exit_success; } { char fixed_mode[5]; php_stream_mode_sanitize_fdopen_fopencookie(stream, fixed_mode); *(FILE**)ret = fopencookie(stream, fixed_mode, PHP_STREAM_COOKIE_FUNCTIONS); } if (*ret != NULL) { zend_off_t pos; stream->fclose_stdiocast = PHP_STREAM_FCLOSE_FOPENCOOKIE; /* If the stream position is not at the start, we need to force * the stdio layer to believe it's real location. */ pos = php_stream_tell(stream); if (pos > 0) { zend_fseek(*ret, pos, SEEK_SET); } goto exit_success; } /* must be either: a) programmer error b) no memory -> lets bail */ php_error_docref(NULL, E_ERROR, "fopencookie failed"); return FAILURE; #endif if (!php_stream_is_filtered(stream) && stream->ops->cast && stream->ops->cast(stream, castas, NULL) == SUCCESS) { if (FAILURE == stream->ops->cast(stream, castas, ret)) { return FAILURE; } goto exit_success; } else if (flags & PHP_STREAM_CAST_TRY_HARD) { php_stream *newstream; newstream = php_stream_fopen_tmpfile(); if (newstream) { int retcopy = php_stream_copy_to_stream_ex(stream, newstream, PHP_STREAM_COPY_ALL, NULL); if (retcopy != SUCCESS) { php_stream_close(newstream); } else { int retcast = php_stream_cast(newstream, castas | flags, (void **)ret, show_err); if (retcast == SUCCESS) { rewind(*(FILE**)ret); } /* do some specialized cleanup */ if ((flags & PHP_STREAM_CAST_RELEASE)) { php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED); } /* TODO: we probably should be setting .stdiocast and .fclose_stdiocast or * we may be leaking the FILE*. Needs investigation, though. */ return retcast; } } } } if (php_stream_is_filtered(stream)) { php_error_docref(NULL, E_WARNING, "cannot cast a filtered stream on this system"); return FAILURE; } else if (stream->ops->cast && stream->ops->cast(stream, castas, ret) == SUCCESS) { goto exit_success; } if (show_err) { /* these names depend on the values of the PHP_STREAM_AS_XXX defines in php_streams.h */ static const char *cast_names[4] = { "STDIO FILE*", "File Descriptor", "Socket Descriptor", "select()able descriptor" }; php_error_docref(NULL, E_WARNING, "cannot represent a stream of type %s as a %s", stream->ops->label, cast_names[castas]); } return FAILURE; exit_success: if ((stream->writepos - stream->readpos) > 0 && stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE && (flags & PHP_STREAM_CAST_INTERNAL) == 0 ) { /* the data we have buffered will be lost to the third party library that * will be accessing the stream. Emit a warning so that the end-user will * know that they should try something else */ php_error_docref(NULL, E_WARNING, ZEND_LONG_FMT " bytes of buffered data lost during stream conversion!", (zend_long)(stream->writepos - stream->readpos)); } if (castas == PHP_STREAM_AS_STDIO && ret) { stream->stdiocast = *(FILE**)ret; } if (flags & PHP_STREAM_CAST_RELEASE) { php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED); } return SUCCESS; }
/* {{{ inifile_delete_replace_append */ static int inifile_delete_replace_append(inifile *dba, const key_type *key, const val_type *value, int append, zend_bool *found) { size_t pos_grp_start=0, pos_grp_next; inifile *ini_tmp = NULL; php_stream *fp_tmp = NULL; int ret; /* 1) Search group start * 2) Search next group * 3) If not append: Copy group to ini_tmp * 4) Open temp_stream and copy remainder * 5) Truncate stream * 6) If not append AND key.name given: Filtered copy back from ini_tmp * to stream. Otherwise the user wanted to delete the group. * 7) Append value if given * 8) Append temporary stream */ assert(!append || (key->name && value)); /* missuse */ /* 1 - 3 */ inifile_find_group(dba, key, &pos_grp_start); inifile_next_group(dba, key, &pos_grp_next); if (append) { ret = SUCCESS; } else { ret = inifile_copy_to(dba, pos_grp_start, pos_grp_next, &ini_tmp); } /* 4 */ if (ret == SUCCESS) { fp_tmp = php_stream_temp_create(0, 64 * 1024); if (!fp_tmp) { php_error_docref(NULL, E_WARNING, "Could not create temporary stream"); ret = FAILURE; } else { php_stream_seek(dba->fp, 0, SEEK_END); if (pos_grp_next != (size_t)php_stream_tell(dba->fp)) { php_stream_seek(dba->fp, pos_grp_next, SEEK_SET); if (SUCCESS != php_stream_copy_to_stream_ex(dba->fp, fp_tmp, PHP_STREAM_COPY_ALL, NULL)) { php_error_docref(NULL, E_WARNING, "Could not copy remainder to temporary stream"); ret = FAILURE; } } } } /* 5 */ if (ret == SUCCESS) { if (!value || (key->name && strlen(key->name))) { ret = inifile_truncate(dba, append ? pos_grp_next : pos_grp_start); /* writes error on fail */ } } if (ret == SUCCESS) { if (key->name && strlen(key->name)) { /* 6 */ if (!append && ini_tmp) { ret = inifile_filter(dba, ini_tmp, key, found); } /* 7 */ /* important: do not query ret==SUCCESS again: inifile_filter might fail but * however next operation must be done. */ if (value) { if (pos_grp_start == pos_grp_next && key->group && strlen(key->group)) { php_stream_printf(dba->fp, "[%s]\n", key->group); } php_stream_printf(dba->fp, "%s=%s\n", key->name, value->value ? value->value : ""); } } /* 8 */ /* important: do not query ret==SUCCESS again: inifile_filter might fail but * however next operation must be done. */ if (fp_tmp && php_stream_tell(fp_tmp)) { php_stream_seek(fp_tmp, 0, SEEK_SET); php_stream_seek(dba->fp, 0, SEEK_END); if (SUCCESS != php_stream_copy_to_stream_ex(fp_tmp, dba->fp, PHP_STREAM_COPY_ALL, NULL)) { zend_throw_error(NULL, "Could not copy from temporary stream - ini file truncated"); ret = FAILURE; } } } if (ini_tmp) { php_stream_close(ini_tmp->fp); inifile_free(ini_tmp, 0); } if (fp_tmp) { php_stream_close(fp_tmp); } php_stream_flush(dba->fp); php_stream_seek(dba->fp, 0, SEEK_SET); return ret; }