@@ -862,6 +862,7 @@ read_directory(PyObject *archive)
862862 long l , count ;
863863 Py_ssize_t i ;
864864 char name [MAXPATHLEN + 5 ];
865+ char dummy [8 ]; /* Buffer to read unused header values into */
865866 PyObject * nameobj = NULL ;
866867 char * p , endof_central_dir [22 ];
867868 Py_ssize_t arc_offset ; /* Absolute offset to start of the zip-archive. */
@@ -905,17 +906,23 @@ read_directory(PyObject *archive)
905906
906907 /* Start of Central Directory */
907908 count = 0 ;
909+ if (fseek (fp , header_offset , 0 ) == -1 )
910+ goto file_error ;
908911 for (;;) {
909912 PyObject * t ;
910913 int err ;
911914
912- if (fseek (fp , header_offset , 0 ) == -1 ) /* Start of file header */
913- goto fseek_error ;
915+ /* Start of file header */
914916 l = PyMarshal_ReadLongFromFile (fp );
915917 if (l != 0x02014B50 )
916918 break ; /* Bad: Central Dir File Header */
917- if (fseek (fp , header_offset + 8 , 0 ) == -1 )
918- goto fseek_error ;
919+
920+ /* On Windows, calling fseek to skip over the fields we don't use is
921+ slower than reading the data into a dummy buffer because fseek flushes
922+ stdio's internal buffers. See issue #8745. */
923+ if (fread (dummy , 1 , 4 , fp ) != 4 ) /* Skip unused fields, avoid fseek */
924+ goto file_error ;
925+
919926 flags = (unsigned short )PyMarshal_ReadShortFromFile (fp );
920927 compress = PyMarshal_ReadShortFromFile (fp );
921928 time = PyMarshal_ReadShortFromFile (fp );
@@ -924,11 +931,11 @@ read_directory(PyObject *archive)
924931 data_size = PyMarshal_ReadLongFromFile (fp );
925932 file_size = PyMarshal_ReadLongFromFile (fp );
926933 name_size = PyMarshal_ReadShortFromFile (fp );
927- header_size = 46 + name_size +
934+ header_size = name_size +
928935 PyMarshal_ReadShortFromFile (fp ) +
929936 PyMarshal_ReadShortFromFile (fp );
930- if (fseek ( fp , header_offset + 42 , 0 ) == -1 )
931- goto fseek_error ;
937+ if (fread ( dummy , 1 , 8 , fp ) != 8 ) /* Skip unused fields, avoid fseek */
938+ goto file_error ;
932939 file_offset = PyMarshal_ReadLongFromFile (fp ) + arc_offset ;
933940 if (name_size > MAXPATHLEN )
934941 name_size = MAXPATHLEN ;
@@ -941,7 +948,9 @@ read_directory(PyObject *archive)
941948 p ++ ;
942949 }
943950 * p = 0 ; /* Add terminating null byte */
944- header_offset += header_size ;
951+ for (; i < header_size ; i ++ ) /* Skip the rest of the header */
952+ if (getc (fp ) == EOF ) /* Avoid fseek */
953+ goto file_error ;
945954
946955 bootstrap = 0 ;
947956 if (flags & 0x0800 )
@@ -988,7 +997,7 @@ read_directory(PyObject *archive)
988997 PySys_FormatStderr ("# zipimport: found %ld names in %R\n" ,
989998 count , archive );
990999 return files ;
991- fseek_error :
1000+ file_error :
9921001 fclose (fp );
9931002 Py_XDECREF (files );
9941003 Py_XDECREF (nameobj );
0 commit comments