Author: Amaury Forgeot d'Arc <[email protected]>
Branch: py3.5
Changeset: r88369:9ffa558330fb
Date: 2016-11-13 23:22 +0100
http://bitbucket.org/pypy/pypy/changeset/9ffa558330fb/
Log: CPython issue #21679: Prevent extraneous fstat() calls during
open().
diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py
--- a/pypy/module/_io/interp_fileio.py
+++ b/pypy/module/_io/interp_fileio.py
@@ -5,9 +5,13 @@
from rpython.rlib.rarithmetic import r_longlong
from rpython.rlib.rstring import StringBuilder
from rpython.rlib import rposix
+from rpython.rlib.rposix_stat import STAT_FIELD_TYPES
from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, O_EXCL
import sys, os, stat, errno
-from pypy.module._io.interp_iobase import W_RawIOBase, convert_size
+from pypy.module._io.interp_iobase import (
+ W_RawIOBase, convert_size, DEFAULT_BUFFER_SIZE)
+
+HAS_BLKSIZE = 'st_blksize' in STAT_FIELD_TYPES
def interp_member_w(name, cls, doc=None):
"NOT_RPYTHON: initialization-time only"
@@ -162,12 +166,6 @@
fd_is_own = False
try:
if fd >= 0:
- try:
- os.fstat(fd)
- except OSError as e:
- if e.errno == errno.EBADF:
- raise wrap_oserror(space, e)
- # else: pass
self.fd = fd
self.closefd = bool(closefd)
elif space.is_none(w_opener):
@@ -207,7 +205,20 @@
except OSError as e:
raise wrap_oserror2(space, e, w_name)
- self._dircheck(space, w_name)
+ try:
+ st = os.fstat(self.fd)
+ except OSError as e:
+ raise wrap_oserror(space, e)
+ # On Unix, fopen will succeed for directories.
+ # In Python, there should be no file objects referring to
+ # directories, so we need a check.
+ if stat.S_ISDIR(st.st_mode):
+ raise wrap_oserror2(space, OSError(errno.EISDIR, "fstat"),
+ w_name, exception_name='w_IOError')
+ self.blksize = DEFAULT_BUFFER_SIZE
+ if HAS_BLKSIZE and st.st_blksize > 1:
+ self.blksize = st.st_blksize
+
space.setattr(self, space.wrap("name"), w_name)
if self.appending:
@@ -244,6 +255,9 @@
def descr_get_mode(self, space):
return space.wrap(self._mode())
+ def get_blksize(self, space):
+ return space.wrap(self.blksize)
+
def _closed(self, space):
return self.fd < 0
@@ -298,20 +312,6 @@
if e.match(space, space.w_Warning):
e.write_unraisable(space, '', space.wrap(self))
- def _dircheck(self, space, w_filename):
- # On Unix, fopen will succeed for directories.
- # In Python, there should be no file objects referring to
- # directories, so we need a check.
- if self.fd < 0:
- return
- try:
- st = os.fstat(self.fd)
- except OSError:
- return
- if stat.S_ISDIR(st.st_mode):
- raise wrap_oserror2(space, OSError(errno.EISDIR, "fstat"),
- w_filename, exception_name='w_IOError')
-
@unwrap_spec(pos=r_longlong, whence=int)
def seek_w(self, space, pos, whence=0):
self._check_closed(space)
@@ -506,5 +506,6 @@
doc="True if the file descriptor will be closed"),
mode = GetSetProperty(W_FileIO.descr_get_mode,
doc="String giving the file mode"),
+ _blksize = GetSetProperty(W_FileIO.get_blksize),
)
diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py
--- a/pypy/module/_io/interp_io.py
+++ b/pypy/module/_io/interp_io.py
@@ -6,9 +6,6 @@
TypeDef, interp_attrproperty, generic_new_descr)
from pypy.module._io.interp_fileio import W_FileIO
from pypy.module._io.interp_textio import W_TextIOWrapper
-from rpython.rlib.rposix_stat import STAT_FIELD_TYPES
-
-HAS_BLKSIZE = 'st_blksize' in STAT_FIELD_TYPES
class Cache:
@@ -17,8 +14,6 @@
"io.UnsupportedOperation",
space.newtuple([space.w_ValueError, space.w_IOError]))
-DEFAULT_BUFFER_SIZE = 8 * 1024
-
@unwrap_spec(mode=str, buffering=int,
encoding="str_or_None", errors="str_or_None",
newline="str_or_None", closefd=int)
@@ -96,18 +91,7 @@
buffering = -1
if buffering < 0:
- buffering = DEFAULT_BUFFER_SIZE
-
- if HAS_BLKSIZE:
- fileno = space.c_int_w(space.call_method(w_raw, "fileno"))
- try:
- st = os.fstat(fileno)
- except OSError:
- # Errors should never pass silently, except this one time.
- pass
- else:
- if st.st_blksize > 1:
- buffering = st.st_blksize
+ buffering = space.c_int_w(space.getattr(w_raw, space.wrap("_blksize")))
if buffering < 0:
raise oefmt(space.w_ValueError, "invalid buffering size")
diff --git a/pypy/module/_io/test/test_fileio.py
b/pypy/module/_io/test/test_fileio.py
--- a/pypy/module/_io/test/test_fileio.py
+++ b/pypy/module/_io/test/test_fileio.py
@@ -21,6 +21,8 @@
assert f.name.endswith('tmpfile')
assert f.mode == 'ab'
assert f.closefd is True
+ assert f._blksize >= 1024
+ assert f._blksize % 1024 == 0
f.close()
def test_invalid_fd(self):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit