diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-09-05 16:35:40 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-09-05 18:29:15 +0200 |
commit | 9ec61e43d453aadab9539f6814e8694295aa1ed1 (patch) | |
tree | 66e1bcfce505809c0263be1431ef55527ab1462e | |
parent | 4ecdff2da829a60ddb01ecb260d688acca7339d4 (diff) | |
download | php-git-9ec61e43d453aadab9539f6814e8694295aa1ed1.tar.gz |
Fix pipe detection and stream position handling
There are two related changes here:
1. Also check for S_ISCHR/FILE_TYPE_CHAR when checking for pipes, so
that we detect ttys as well, which are also not seekable.
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.
-rw-r--r-- | main/streams/plain_wrapper.c | 52 | ||||
-rw-r--r-- | sapi/cli/tests/std_streams.phpt | 31 |
2 files changed, 52 insertions, 31 deletions
diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index bce58f7df2..61b19e48ad 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -242,6 +242,22 @@ 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) { + DWORD file_type = GetFileType((HANDLE)handle); + + self->is_pipe = file_type == FILE_TYPE_PIPE || file_type == FILE_TYPE_CHAR; + } +#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 +265,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 +291,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 0000000000..623cedaed1 --- /dev/null +++ b/sapi/cli/tests/std_streams.phpt @@ -0,0 +1,31 @@ +--TEST-- +Testing ftell() on std streams +--SKIPIF-- +<?php +if (getenv("SKIP_IO_CAPTURE_TESTS")) { + die("skip I/O capture test"); +} +?> +--CAPTURE_STDIO-- +STDOUT +--FILE-- +<?php + +// These have proc_open pipes attached +var_dump(ftell(STDIN)); +var_dump(ftell(STDERR)); +var_dump(ftell(fopen("php://stdin", "r"))); +var_dump(ftell(fopen("php://stderr", "w"))); + +// These have a tty attached +var_dump(ftell(STDOUT)); +var_dump(ftell(fopen("php://stdout", "w"))); + +?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) |