summaryrefslogtreecommitdiff
path: root/main/streams/cast.c
diff options
context:
space:
mode:
authorGustavo André dos Santos Lopes <cataphract@php.net>2010-11-05 01:29:08 +0000
committerGustavo André dos Santos Lopes <cataphract@php.net>2010-11-05 01:29:08 +0000
commit0a351335249697ef3fe0b2f9441cf30ad5cb8499 (patch)
tree5263793b4f3c02dbd87e8e764a4a0326a2c78635 /main/streams/cast.c
parent6f1cfe3e7fe7ebb5f8ef733803ee50bfd4e63ad1 (diff)
downloadphp-git-0a351335249697ef3fe0b2f9441cf30ad5cb8499.tar.gz
- Fixed bug #53241 (stream casting that relies on fdopen/fopencookie fails
with streams opened with, inter alia, the 'xb' mode).
Diffstat (limited to 'main/streams/cast.c')
-rw-r--r--main/streams/cast.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/main/streams/cast.c b/main/streams/cast.c
index e196a005e2..89bfa0ab46 100644
--- a/main/streams/cast.c
+++ b/main/streams/cast.c
@@ -144,6 +144,50 @@ static COOKIE_IO_FUNCTIONS_T stream_cookie_functions =
#endif
/* }}} */
+/* {{{ php_stream_rep_nonstand_mode
+ * Result should have at least size 5, e.g. to write wbx+\0 */
+PHPAPI void php_stream_rep_nonstand_mode(php_stream *stream, char *result)
+{
+ /* replace modes not supported by fdopen and fopencookie, but supported
+ * by PHP's fread(), so that their calls won't fail */
+ const char *cur_mode = stream->mode;
+ int has_plus = 0,
+ has_bin = 0,
+ i,
+ res_curs = 0;
+
+ if (cur_mode[0] == 'r' || cur_mode[0] == 'w' || cur_mode[0] == 'a') {
+ result[res_curs++] = cur_mode[0];
+ } else {
+ /* assume cur_mode[0] is 'c' or 'x'; substitute by 'w', which should not
+ * truncate anything in fdopen/fopencookie */
+ result[res_curs++] = 'w';
+
+ /* x is allowed (at least by glibc & compat), but not as the 1st mode
+ * as in PHP and in any case is (at best) ignored by fdopen and fopencookie */
+ }
+
+ /* assume current mode has at most length 4 (e.g. wbn+) */
+ for (i = 1; i < 4 && cur_mode[i] != '\0'; i++) {
+ if (cur_mode[i] == 'b') {
+ has_bin = 1;
+ } else if (cur_mode[i] == '+') {
+ has_plus = 1;
+ }
+ /* ignore 'n', 't' or other stuff */
+ }
+
+ if (has_bin) {
+ result[res_curs++] = 'b';
+ }
+ if (has_plus) {
+ result[res_curs++] = '+';
+ }
+
+ result[res_curs] = '\0';
+}
+/* }}} */
+
/* {{{ php_stream_cast */
PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC)
{
@@ -187,7 +231,11 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show
goto exit_success;
}
- *(FILE**)ret = fopencookie(stream, stream->mode, PHP_STREAM_COOKIE_FUNCTIONS);
+ {
+ char fixed_mode[5];
+ php_stream_rep_nonstand_mode(stream, fixed_mode);
+ *(FILE**)ret = fopencookie(stream, fixed_mode, PHP_STREAM_COOKIE_FUNCTIONS);
+ }
if (*ret != NULL) {
off_t pos;