mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix bug #72666: stat cache not cleared for plain paths
This adds more aggressive clearing of stat cache. It is added to the filestat as well as plain wrapper operations which covers stream file accessing as well as exec functions (using pipes). It should hopefully fix the most visible issues with the stat cache. Closes GH-17681
This commit is contained in:
4
NEWS
4
NEWS
@@ -62,6 +62,10 @@ PHP NEWS
|
||||
. Fixed bug GH-15902 (Core dumped in ext/reflection/php_reflection.c).
|
||||
(DanielEScherzer)
|
||||
|
||||
- Standard:
|
||||
. Fixed bug #72666 (stat cache clearing inconsistent between file:// paths
|
||||
and plain paths). (Jakub Zelenka)
|
||||
|
||||
- Streams:
|
||||
. Fixed bug GH-17650 (realloc with size 0 in user_filters.c). (nielsdos)
|
||||
. Fix memory leak on overflow in _php_stream_scandir(). (nielsdos)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
19
ext/standard/tests/file/bug72666_variation1.phpt
Normal file
19
ext/standard/tests/file/bug72666_variation1.phpt
Normal file
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
Bug #72666 (stat cache clearing inconsistent - touch)
|
||||
--FILE--
|
||||
<?php
|
||||
$filename = __DIR__ . '/bug72666_variation1.txt';
|
||||
|
||||
touch($filename);
|
||||
var_dump(filemtime($filename) > 2);
|
||||
touch($filename, 1);
|
||||
var_dump(filemtime($filename));
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(__DIR__ . '/bug72666_variation1.txt');
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
int(1)
|
||||
35
ext/standard/tests/file/bug72666_variation2.phpt
Normal file
35
ext/standard/tests/file/bug72666_variation2.phpt
Normal file
@@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
Bug #72666 (stat cache clearing inconsistent - chgrp, chmod)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (substr(PHP_OS, 0, 3) == 'WIN') die('skip no windows support');
|
||||
if (!function_exists("posix_getgid")) die("skip no posix_getgid()");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$filename = __DIR__ . '/bug72666_variation2.txt';
|
||||
|
||||
$gid = posix_getgid();
|
||||
|
||||
var_dump(touch($filename));
|
||||
$ctime1 = filectime($filename);
|
||||
sleep(1);
|
||||
var_dump(chgrp($filename,$gid));
|
||||
$ctime2 = filectime($filename);
|
||||
sleep(1);
|
||||
var_dump(chmod($filename, 0777));
|
||||
$ctime3 = filectime($filename);
|
||||
|
||||
var_dump($ctime2 > $ctime1);
|
||||
var_dump($ctime3 > $ctime2);
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(__DIR__ . '/bug72666_variation2.txt');
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
35
ext/standard/tests/file/bug72666_variation3.phpt
Normal file
35
ext/standard/tests/file/bug72666_variation3.phpt
Normal file
@@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
Bug #72666 (stat cache clearing inconsistent - plain wrapper)
|
||||
--FILE--
|
||||
<?php
|
||||
$filename = __DIR__ . '/bug72666_variation3.txt';
|
||||
|
||||
file_put_contents($filename, "test");
|
||||
$fd = fopen($filename, "r");
|
||||
$atime1 = fileatime($filename);
|
||||
sleep(1);
|
||||
var_dump(fread($fd, 4));
|
||||
$atime2 = fileatime($filename);
|
||||
$mtime1 = filemtime($filename);
|
||||
fclose($fd);
|
||||
$fd = fopen($filename, "w");
|
||||
sleep(1);
|
||||
var_dump(fwrite($fd, "data"));
|
||||
$mtime2 = filemtime($filename);
|
||||
if (substr(PHP_OS, 0, 3) == 'WIN') {
|
||||
// Windows do not hundle atime
|
||||
var_dump($atime2 == $atime1);
|
||||
} else {
|
||||
var_dump($atime2 > $atime1);
|
||||
}
|
||||
var_dump($mtime2 > $mtime1);
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(__DIR__ . '/bug72666_variation3.txt');
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4) "test"
|
||||
int(4)
|
||||
bool(true)
|
||||
bool(true)
|
||||
26
ext/standard/tests/file/bug72666_variation4.phpt
Normal file
26
ext/standard/tests/file/bug72666_variation4.phpt
Normal file
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
Bug #72666 (stat cache clearing inconsistent - exec)
|
||||
--FILE--
|
||||
<?php
|
||||
$filename = __DIR__ . '/bug72666_variation4.txt';
|
||||
|
||||
touch($filename, 1);
|
||||
var_dump(filemtime($filename));
|
||||
exec("touch $filename");
|
||||
var_dump(filemtime($filename) > 1);
|
||||
|
||||
|
||||
touch($filename, 1);
|
||||
var_dump(filemtime($filename));
|
||||
shell_exec("touch $filename");
|
||||
var_dump(filemtime($filename) > 1);
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
unlink(__DIR__ . '/bug72666_variation4.txt');
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
||||
bool(true)
|
||||
int(1)
|
||||
bool(true)
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user