mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
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.
This commit is contained in:
parent
4ecdff2da8
commit
9ec61e43d4
2 changed files with 52 additions and 31 deletions
|
@ -242,6 +242,22 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC)
|
||||||
return php_stream_fopen_temporary_file(NULL, "php", NULL);
|
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)
|
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);
|
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) {
|
if (stream) {
|
||||||
php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
|
php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
|
||||||
|
|
||||||
#ifdef S_ISFIFO
|
detect_is_pipe(self);
|
||||||
/* 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
|
|
||||||
|
|
||||||
if (self->is_pipe) {
|
if (self->is_pipe) {
|
||||||
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
|
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
|
||||||
|
stream->position = -1;
|
||||||
} else {
|
} else {
|
||||||
stream->position = zend_lseek(self->fd, 0, SEEK_CUR);
|
stream->position = zend_lseek(self->fd, 0, SEEK_CUR);
|
||||||
#ifdef ESPIPE
|
#ifdef ESPIPE
|
||||||
|
/* FIXME: Is this code still needed? */
|
||||||
if (stream->position == (zend_off_t)-1 && errno == ESPIPE) {
|
if (stream->position == (zend_off_t)-1 && errno == ESPIPE) {
|
||||||
stream->position = 0;
|
|
||||||
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
|
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
|
||||||
self->is_pipe = 1;
|
self->is_pipe = 1;
|
||||||
}
|
}
|
||||||
|
@ -288,23 +291,10 @@ PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STRE
|
||||||
if (stream) {
|
if (stream) {
|
||||||
php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
|
php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
|
||||||
|
|
||||||
#ifdef S_ISFIFO
|
detect_is_pipe(self);
|
||||||
/* 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
|
|
||||||
|
|
||||||
if (self->is_pipe) {
|
if (self->is_pipe) {
|
||||||
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
|
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
|
||||||
|
stream->position = -1;
|
||||||
} else {
|
} else {
|
||||||
stream->position = zend_ftell(file);
|
stream->position = zend_ftell(file);
|
||||||
}
|
}
|
||||||
|
|
31
sapi/cli/tests/std_streams.phpt
Normal file
31
sapi/cli/tests/std_streams.phpt
Normal file
|
@ -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)
|
Loading…
Add table
Add a link
Reference in a new issue