summaryrefslogtreecommitdiff
path: root/main/streams.c
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2002-10-05 10:35:13 +0000
committerWez Furlong <wez@php.net>2002-10-05 10:35:13 +0000
commit077fe52d8b650b5d1739aa55ab90f6ab6ad8461b (patch)
tree90af179612cfc891683ba1fbf5ba8d66874b93bf /main/streams.c
parent945ccfa76a8453ffc8fe4e514ef593c95fe377eb (diff)
downloadphp-git-077fe52d8b650b5d1739aa55ab90f6ab6ad8461b.tar.gz
This seems to resolve the issues with fgets.
I've moved EOF detection into the streams layer; a stream reader implementation should set stream->eof when it detects EOF. Fixed test for user streams - it still fails but that is due to an output buffering bug.
Diffstat (limited to 'main/streams.c')
-rwxr-xr-xmain/streams.c131
1 files changed, 91 insertions, 40 deletions
diff --git a/main/streams.c b/main/streams.c
index 8a23938aaf..1620628801 100755
--- a/main/streams.c
+++ b/main/streams.c
@@ -462,8 +462,8 @@ static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_D
/* allocate/fill the buffer */
/* is there enough data in the buffer ? */
- while (stream->writepos - stream->readpos < (off_t)size) {
- size_t justread;
+ if (stream->writepos - stream->readpos < (off_t)size) {
+ size_t justread = 0;
/* no; so lets fetch more data */
@@ -491,21 +491,21 @@ static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_D
stream->readbuflen - stream->writepos
TSRMLS_CC);
}
-
- if (justread <= 0)
- break;
-
- stream->writepos += justread;
-
- if (stream->flags & PHP_STREAM_FLAG_AVOID_BLOCKING)
- break;
+
+ if (justread > 0) {
+ stream->writepos += justread;
+ }
}
+
}
PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC)
{
size_t toread, didread = 0;
+ if (size == 0)
+ return 0;
+
/* take from the read buffer first.
* It is possible that a buffered stream was switched to non-buffered, so we
* drain the remainder of the buffer before using the "raw" read mode for
@@ -525,6 +525,10 @@ PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS
if (size == 0) {
stream->position += didread;
+
+ if (didread == 0)
+ stream->eof = 1;
+
return didread;
}
@@ -549,6 +553,10 @@ PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS
}
}
stream->position += size;
+
+ if (didread == 0)
+ stream->eof = 1;
+
return didread;
}
@@ -558,6 +566,8 @@ PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC)
if (stream->writepos - stream->readpos > 0)
return 0;
+ return stream->eof;
+
/* we define our stream reading function so that it
must return EOF when an EOF condition occurs, when
working in unbuffered mode and called with these args */
@@ -657,7 +667,7 @@ PHPAPI char *_php_stream_gets(php_stream *stream, char *buf, size_t maxlen TSRML
{
size_t avail = 0;
int did_copy = 0;
-
+
if (maxlen == 0)
return NULL;
@@ -779,6 +789,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_
if (offset > 0 && offset < stream->writepos - stream->readpos) {
stream->readpos += offset;
stream->position += offset;
+ stream->eof = 0;
return 0;
}
break;
@@ -787,6 +798,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_
offset < stream->position + stream->writepos - stream->readpos) {
stream->readpos += offset - stream->position;
stream->position = offset;
+ stream->eof = 0;
return 0;
}
break;
@@ -809,8 +821,11 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_
}
ret = stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC);
- if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0)
+ if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0) {
+ if (ret == 0)
+ stream->eof = 0;
return ret;
+ }
/* else the stream has decided that it can't support seeking after all;
* fall through to attempt emulation */
}
@@ -827,6 +842,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_
if (php_stream_read(stream, tmp, offset) == 0)
return -1;
}
+ stream->eof = 0;
return 0;
}
@@ -1100,6 +1116,7 @@ PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size
typedef struct {
FILE *file;
+ int fd; /* underlying file descriptor */
int is_process_pipe; /* use pclose instead of fclose */
int is_pipe; /* don't try and seek */
#if HAVE_FLUSHIO
@@ -1149,21 +1166,19 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC)
PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
{
php_stdio_stream_data *self;
-#ifdef S_ISFIFO
- int fd;
-#endif
self = emalloc_rel_orig(sizeof(*self));
self->file = file;
self->is_pipe = 0;
self->is_process_pipe = 0;
+ self->fd = fileno(file);
+
#ifdef S_ISFIFO
/* detect if this is a pipe */
- fd = fileno(file);
- if (fd >= 0) {
+ if (self->fd >= 0) {
struct stat sb;
- self->is_pipe = (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) ? 1 : 0;
+ self->is_pipe = (fstat(self->fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) ? 1 : 0;
}
#endif
@@ -1178,6 +1193,8 @@ PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STRE
self->file = file;
self->is_pipe = 1;
self->is_process_pipe = 1;
+ self->fd = fileno(file);
+
return php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
}
@@ -1187,37 +1204,48 @@ static size_t php_stdiop_write(php_stream *stream, const char *buf, size_t count
assert(data != NULL);
+ if (data->fd >= 0) {
+
+ return write(data->fd, buf, count);
+
+ } else {
+
#if HAVE_FLUSHIO
- if (!data->is_pipe && data->last_op == 'r') {
- fseek(data->file, 0, SEEK_CUR);
- }
- data->last_op = 'w';
+ if (!data->is_pipe && data->last_op == 'r') {
+ fseek(data->file, 0, SEEK_CUR);
+ }
+ data->last_op = 'w';
#endif
- return fwrite(buf, 1, count, data->file);
+ return fwrite(buf, 1, count, data->file);
+ }
}
static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
{
php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
+ size_t ret;
assert(data != NULL);
- if (buf == NULL && count == 0) {
- /* check for EOF condition */
- if (feof(data->file)) {
- return EOF;
- }
- return 0;
- }
-
+ if (data->fd >= 0) {
+ ret = read(data->fd, buf, count);
+
+ if (ret == 0 || (ret < 0 && errno != EWOULDBLOCK))
+ stream->eof = 1;
+
+ } else {
#if HAVE_FLUSHIO
- if (!data->is_pipe && data->last_op == 'w')
- fseek(data->file, 0, SEEK_CUR);
- data->last_op = 'r';
+ if (!data->is_pipe && data->last_op == 'w')
+ fseek(data->file, 0, SEEK_CUR);
+ data->last_op = 'r';
#endif
- return fread(buf, 1, count, data->file);
+ ret = fread(buf, 1, count, data->file);
+
+ if (ret == 0 && feof(data->file))
+ stream->eof = 1;
+ }
}
static int php_stdiop_close(php_stream *stream, int close_handle TSRMLS_DC)
@@ -1249,7 +1277,11 @@ static int php_stdiop_flush(php_stream *stream TSRMLS_DC)
assert(data != NULL);
- return fflush(data->file);
+ if (data->fd >= 0) {
+ return fsync(data->fd);
+ } else {
+ return fflush(data->file);
+ }
}
static int php_stdiop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
@@ -1263,10 +1295,22 @@ static int php_stdiop_seek(php_stream *stream, off_t offset, int whence, off_t *
php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot seek on a pipe");
return -1;
}
-
- ret = fseek(data->file, offset, whence);
- *newoffset = ftell(data->file);
- return ret;
+
+ if (data->fd >= 0) {
+ off_t result;
+
+ result = lseek(data->fd, offset, whence);
+ if (result == (off_t)-1)
+ return -1;
+
+ *newoffset = result;
+ return 0;
+
+ } else {
+ ret = fseek(data->file, offset, whence);
+ *newoffset = ftell(data->file);
+ return ret;
+ }
}
static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
@@ -1275,15 +1319,22 @@ static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
assert(data != NULL);
+
+ /* as soon as someone touches the stdio layer, buffering may ensue,
+ * so we need to stop using the fd directly in that case */
switch (castas) {
case PHP_STREAM_AS_STDIO:
if (ret) {
*ret = data->file;
+ data->fd = -1;
}
return SUCCESS;
case PHP_STREAM_AS_FD:
+ /* fetch the fileno rather than using data->fd, since we may
+ * have zeroed that member if someone requested the FILE*
+ * first (see above case) */
fd = fileno(data->file);
if (fd < 0) {
return FAILURE;