diff --git a/ext/standard/filestat.c b/ext/standard/filestat.c index 1d83dcfe940df..9b8ff7efd6a66 100644 --- a/ext/standard/filestat.c +++ b/ext/standard/filestat.c @@ -388,6 +388,9 @@ static void php_do_chgrp(INTERNAL_FUNCTION_PARAMETERS, int do_lchgrp) /* {{{ */ php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); RETURN_FALSE; } + + php_clear_stat_cache(0, NULL, 0); + RETURN_TRUE; #endif } @@ -527,6 +530,9 @@ static void php_do_chown(INTERNAL_FUNCTION_PARAMETERS, int do_lchown) /* {{{ */ php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); RETURN_FALSE; } + + php_clear_stat_cache(0, NULL, 0); + RETURN_TRUE; #endif } @@ -591,6 +597,9 @@ PHP_FUNCTION(chmod) php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); RETURN_FALSE; } + + php_clear_stat_cache(0, NULL, 0); + RETURN_TRUE; } /* }}} */ @@ -676,6 +685,9 @@ PHP_FUNCTION(touch) php_error_docref(NULL, E_WARNING, "Utime failed: %s", strerror(errno)); RETURN_FALSE; } + + php_clear_stat_cache(0, NULL, 0); + RETURN_TRUE; } /* }}} */ diff --git a/ext/standard/tests/file/bug72666_variation1.phpt b/ext/standard/tests/file/bug72666_variation1.phpt new file mode 100644 index 0000000000000..6e59405d14ca8 --- /dev/null +++ b/ext/standard/tests/file/bug72666_variation1.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #72666 (stat cache clearing inconsistent - touch) +--FILE-- + 2); +touch($filename, 1); +var_dump(filemtime($filename)); + +?> +--CLEAN-- + +--EXPECT-- +bool(true) +int(1) diff --git a/ext/standard/tests/file/bug72666_variation2.phpt b/ext/standard/tests/file/bug72666_variation2.phpt new file mode 100644 index 0000000000000..7621133c71b24 --- /dev/null +++ b/ext/standard/tests/file/bug72666_variation2.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #72666 (stat cache clearing inconsistent - chgrp, chmod) +--SKIPIF-- + +--FILE-- + $ctime1); +var_dump($ctime3 > $ctime2); +?> +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/standard/tests/file/bug72666_variation3.phpt b/ext/standard/tests/file/bug72666_variation3.phpt new file mode 100644 index 0000000000000..a491640c4f746 --- /dev/null +++ b/ext/standard/tests/file/bug72666_variation3.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #72666 (stat cache clearing inconsistent - plain wrapper) +--FILE-- + $atime1); +} +var_dump($mtime2 > $mtime1); +?> +--CLEAN-- + +--EXPECT-- +string(4) "test" +int(4) +bool(true) +bool(true) diff --git a/ext/standard/tests/file/bug72666_variation4.phpt b/ext/standard/tests/file/bug72666_variation4.phpt new file mode 100644 index 0000000000000..09e32dafed9cf --- /dev/null +++ b/ext/standard/tests/file/bug72666_variation4.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #72666 (stat cache clearing inconsistent - exec) +--FILE-- + 1); + + +touch($filename, 1); +var_dump(filemtime($filename)); +shell_exec("touch $filename"); +var_dump(filemtime($filename) > 1); +?> +--CLEAN-- + +--EXPECT-- +int(1) +bool(true) +int(1) +bool(true) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 83a1b9fed49d5..1d5b7cfdac40d 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -349,14 +349,15 @@ PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STRE static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t count) { php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; + ssize_t bytes_written; assert(data != NULL); if (data->fd >= 0) { #ifdef PHP_WIN32 - ssize_t bytes_written = _write(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count)); + bytes_written = _write(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count)); #else - ssize_t bytes_written = write(data->fd, buf, count); + bytes_written = write(data->fd, buf, count); #endif if (bytes_written < 0) { if (PHP_IS_TRANSIENT_ERROR(errno)) { @@ -370,7 +371,6 @@ static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t coun php_error_docref(NULL, E_NOTICE, "Write of %zu bytes failed with errno=%d %s", count, errno, strerror(errno)); } } - return bytes_written; } else { #ifdef HAVE_FLUSHIO @@ -380,8 +380,15 @@ static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t coun data->last_op = 'w'; #endif - return (ssize_t) fwrite(buf, 1, count, data->file); + bytes_written = (ssize_t) fwrite(buf, 1, count, data->file); } + + if (EG(active)) { + /* clear stat cache as mtime and ctime got changed */ + php_clear_stat_cache(0, NULL, 0); + } + + return bytes_written; } static ssize_t php_stdiop_read(php_stream *stream, char *buf, size_t count) @@ -460,6 +467,12 @@ static ssize_t php_stdiop_read(php_stream *stream, char *buf, size_t count) stream->eof = feof(data->file); } + + if (EG(active)) { + /* clear stat cache as atime got changed */ + php_clear_stat_cache(0, NULL, 0); + } + return ret; } @@ -540,6 +553,10 @@ static int php_stdiop_flush(php_stream *stream) * something completely different. */ if (data->file) { + if (EG(active)) { + /* clear stat cache as there might be a write so mtime and ctime might have changed */ + php_clear_stat_cache(0, NULL, 0); + } return fflush(data->file); } return 0; @@ -1154,6 +1171,12 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, zen ret = php_stream_fopen_from_fd_rel(fd, mode, persistent_id, (open_flags & O_APPEND) == 0); } + if (EG(active)) { + /* clear stat cache as mtime and ctime might got changed - phar can use stream before + * cache is initialized so we need to check if the execution is active. */ + php_clear_stat_cache(0, NULL, 0); + } + if (ret) { if (opened_path) { *opened_path = zend_string_init(realpath, strlen(realpath), 0);