From e04f587594e2e5f244f832f573b10eb90fb247ff Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 5 Sep 2019 16:35:40 +0200 Subject: [PATCH 1/2] Fix pipe detection and stream position handling There are two related changes here: 1. Also check for S_ISCHR when checking for pipes on linux, otherwise we will not detect ttys. 2. Always set position=-1 (i.e. ftell will return false) when a pipe is detected. Previously position=0 was sometimes used, depending on whether we're on Windows/Linux and whether the FD or FILE codepath was used. --- main/streams/plain_wrapper.c | 50 +++++++++++++-------------------- sapi/cli/tests/std_streams.phpt | 31 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 31 deletions(-) create mode 100644 sapi/cli/tests/std_streams.phpt diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index bce58f7df2b7e..bc24423aabd59 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -242,6 +242,20 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC) return php_stream_fopen_temporary_file(NULL, "php", NULL); } +static void detect_is_pipe(php_stdio_stream_data *self) { +#if defined(S_ISFIFO) && defined(S_ISCHR) + if (self->fd >= 0 && do_fstat(self, 0) == 0) { + self->is_pipe = S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode); + } +#elif defined(PHP_WIN32) + zend_uintptr_t handle = _get_osfhandle(self->fd); + + if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) { + self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE; + } +#endif +} + PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC) { php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id); @@ -249,28 +263,15 @@ PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const cha if (stream) { php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract; -#ifdef S_ISFIFO - /* detect if this is a pipe */ - if (self->fd >= 0) { - self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0; - } -#elif defined(PHP_WIN32) - { - zend_uintptr_t handle = _get_osfhandle(self->fd); - - if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) { - self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE; - } - } -#endif - + detect_is_pipe(self); if (self->is_pipe) { stream->flags |= PHP_STREAM_FLAG_NO_SEEK; + stream->position = -1; } else { stream->position = zend_lseek(self->fd, 0, SEEK_CUR); #ifdef ESPIPE + /* FIXME: Is this code still needed? */ if (stream->position == (zend_off_t)-1 && errno == ESPIPE) { - stream->position = 0; stream->flags |= PHP_STREAM_FLAG_NO_SEEK; self->is_pipe = 1; } @@ -288,23 +289,10 @@ PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STRE if (stream) { php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract; -#ifdef S_ISFIFO - /* detect if this is a pipe */ - if (self->fd >= 0) { - self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0; - } -#elif defined(PHP_WIN32) - { - zend_uintptr_t handle = _get_osfhandle(self->fd); - - if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) { - self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE; - } - } -#endif - + detect_is_pipe(self); if (self->is_pipe) { stream->flags |= PHP_STREAM_FLAG_NO_SEEK; + stream->position = -1; } else { stream->position = zend_ftell(file); } diff --git a/sapi/cli/tests/std_streams.phpt b/sapi/cli/tests/std_streams.phpt new file mode 100644 index 0000000000000..623cedaed17ff --- /dev/null +++ b/sapi/cli/tests/std_streams.phpt @@ -0,0 +1,31 @@ +--TEST-- +Testing ftell() on std streams +--SKIPIF-- + +--CAPTURE_STDIO-- +STDOUT +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) From d05deaad69dfc1e578bd690923cb573c2e6583c9 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 5 Sep 2019 17:17:11 +0200 Subject: [PATCH 2/2] Apply additional patch by cmb --- main/streams/plain_wrapper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index bc24423aabd59..61b19e48ad0b4 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -251,7 +251,9 @@ static void detect_is_pipe(php_stdio_stream_data *self) { zend_uintptr_t handle = _get_osfhandle(self->fd); if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) { - self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE; + DWORD file_type = GetFileType((HANDLE)handle); + + self->is_pipe = file_type == FILE_TYPE_PIPE || file_type == FILE_TYPE_CHAR; } #endif }