]> granicus.if.org Git - php/commitdiff
Avoid duplicate fstat() for includes
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 17 Jul 2019 12:43:53 +0000 (14:43 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 17 Jul 2019 12:48:51 +0000 (14:48 +0200)
By adding a flag to avoid forced fstat for includes. The two fstats
will happen back to back and we don't care about a possible
invalidation.

I was hoping to move this higher up in the stack and make the
ISREG check somewhere in fsizer of fixup, but this doesn't really
seem to be possible. E.g. an FP stdin handle will not be a regular
file but of course needs to be allowed. Additionally custom stream
wrappers may not implement this functionality.

main/streams/plain_wrapper.c

index 1bfb2129dc4d8b320aff383f1c60439915e0bde0..e0bc980e5d0bf6112e96b5f2b0c66418e7c49e45 100644 (file)
@@ -128,6 +128,7 @@ typedef struct {
        unsigned is_pipe:1;                     /* don't try and seek */
        unsigned cached_fstat:1;        /* sb is valid */
        unsigned is_pipe_blocking:1; /* allow blocking read() on pipes, currently Windows only */
+       unsigned no_forced_fstat:1;  /* Use fstat cache even if forced */
        unsigned _reserved:28;
 
        int lock_flag;                  /* stores the lock state */
@@ -152,7 +153,7 @@ typedef struct {
 
 static int do_fstat(php_stdio_stream_data *d, int force)
 {
-       if (!d->cached_fstat || force) {
+       if (!d->cached_fstat || (force && !d->no_forced_fstat)) {
                int fd;
                int r;
 
@@ -1079,6 +1080,10 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, zen
                                        php_stream_close(ret);
                                        return NULL;
                                }
+
+                               /* Make sure the fstat result is reused when we later try to get the
+                                * file size. */
+                               self->no_forced_fstat = 1;
                        }
 
                        if (options & STREAM_USE_BLOCKING_PIPE) {