Skip to content

Commit e04f587

Browse files
committed
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.
1 parent a2c21e1 commit e04f587

File tree

2 files changed

+50
-31
lines changed

2 files changed

+50
-31
lines changed

main/streams/plain_wrapper.c

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -242,35 +242,36 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC)
242242
return php_stream_fopen_temporary_file(NULL, "php", NULL);
243243
}
244244

245+
static void detect_is_pipe(php_stdio_stream_data *self) {
246+
#if defined(S_ISFIFO) && defined(S_ISCHR)
247+
if (self->fd >= 0 && do_fstat(self, 0) == 0) {
248+
self->is_pipe = S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode);
249+
}
250+
#elif defined(PHP_WIN32)
251+
zend_uintptr_t handle = _get_osfhandle(self->fd);
252+
253+
if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
254+
self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
255+
}
256+
#endif
257+
}
258+
245259
PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC)
246260
{
247261
php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
248262

249263
if (stream) {
250264
php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
251265

252-
#ifdef S_ISFIFO
253-
/* detect if this is a pipe */
254-
if (self->fd >= 0) {
255-
self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
256-
}
257-
#elif defined(PHP_WIN32)
258-
{
259-
zend_uintptr_t handle = _get_osfhandle(self->fd);
260-
261-
if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
262-
self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
263-
}
264-
}
265-
#endif
266-
266+
detect_is_pipe(self);
267267
if (self->is_pipe) {
268268
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
269+
stream->position = -1;
269270
} else {
270271
stream->position = zend_lseek(self->fd, 0, SEEK_CUR);
271272
#ifdef ESPIPE
273+
/* FIXME: Is this code still needed? */
272274
if (stream->position == (zend_off_t)-1 && errno == ESPIPE) {
273-
stream->position = 0;
274275
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
275276
self->is_pipe = 1;
276277
}
@@ -288,23 +289,10 @@ PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STRE
288289
if (stream) {
289290
php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
290291

291-
#ifdef S_ISFIFO
292-
/* detect if this is a pipe */
293-
if (self->fd >= 0) {
294-
self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
295-
}
296-
#elif defined(PHP_WIN32)
297-
{
298-
zend_uintptr_t handle = _get_osfhandle(self->fd);
299-
300-
if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
301-
self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
302-
}
303-
}
304-
#endif
305-
292+
detect_is_pipe(self);
306293
if (self->is_pipe) {
307294
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
295+
stream->position = -1;
308296
} else {
309297
stream->position = zend_ftell(file);
310298
}

sapi/cli/tests/std_streams.phpt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
Testing ftell() on std streams
3+
--SKIPIF--
4+
<?php
5+
if (getenv("SKIP_IO_CAPTURE_TESTS")) {
6+
die("skip I/O capture test");
7+
}
8+
?>
9+
--CAPTURE_STDIO--
10+
STDOUT
11+
--FILE--
12+
<?php
13+
14+
// These have proc_open pipes attached
15+
var_dump(ftell(STDIN));
16+
var_dump(ftell(STDERR));
17+
var_dump(ftell(fopen("php://stdin", "r")));
18+
var_dump(ftell(fopen("php://stderr", "w")));
19+
20+
// These have a tty attached
21+
var_dump(ftell(STDOUT));
22+
var_dump(ftell(fopen("php://stdout", "w")));
23+
24+
?>
25+
--EXPECT--
26+
bool(false)
27+
bool(false)
28+
bool(false)
29+
bool(false)
30+
bool(false)
31+
bool(false)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy