[pypy-commit] pypy default: check file mode before read/write

bdkearns noreply at buildbot.pypy.org
Fri Aug 29 19:31:39 CEST 2014


Author: Brian Kearns <bdkearns at gmail.com>
Branch: 
Changeset: r73182:7dd943c6998d
Date: 2014-08-29 13:25 -0400
http://bitbucket.org/pypy/pypy/changeset/7dd943c6998d/

Log:	check file mode before read/write

diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -30,6 +30,8 @@
     w_name   = None
     mode     = "<uninitialized file>"
     binary   = False
+    readable = False
+    writable = False
     softspace= 0     # Required according to file object docs
     encoding = None
     errors   = None
@@ -61,6 +63,12 @@
         self.fd = fd
         self.mode = mode
         self.binary = "b" in mode
+        if 'r' in mode or 'U' in mode:
+            self.readable = True
+        if 'w' in mode or 'a' in mode:
+            self.writable = True
+        if '+' in mode:
+            self.readable = self.writable = True
         if w_name is not None:
             self.w_name = w_name
         self.stream = stream
@@ -89,6 +97,16 @@
                 self.space.wrap("I/O operation on closed file")
             )
 
+    def check_readable(self):
+        if not self.readable:
+            raise OperationError(self.space.w_IOError, self.space.wrap(
+                "File not open for reading"))
+
+    def check_writable(self):
+        if not self.writable:
+            raise OperationError(self.space.w_IOError, self.space.wrap(
+                "File not open for writing"))
+
     def getstream(self):
         """Return self.stream or raise an app-level ValueError if missing
         (i.e. if the file is closed)."""
@@ -176,6 +194,7 @@
     @unwrap_spec(n=int)
     def direct_read(self, n=-1):
         stream = self.getstream()
+        self.check_readable()
         if n < 0:
             return stream.readall()
         else:
@@ -201,6 +220,7 @@
     @unwrap_spec(size=int)
     def direct_readline(self, size=-1):
         stream = self.getstream()
+        self.check_readable()
         if size < 0:
             return stream.readline()
         else:
@@ -227,6 +247,7 @@
     @unwrap_spec(size=int)
     def direct_readlines(self, size=0):
         stream = self.getstream()
+        self.check_readable()
         # this is implemented as: .read().split('\n')
         # except that it keeps the \n in the resulting strings
         if size <= 0:
@@ -260,6 +281,7 @@
 
     def direct_truncate(self, w_size=None):  # note: a wrapped size!
         stream = self.getstream()
+        self.check_writable()
         space = self.space
         if space.is_none(w_size):
             size = stream.tell()
@@ -269,6 +291,7 @@
 
     def direct_write(self, w_data):
         space = self.space
+        self.check_writable()
         if self.binary:
             data = space.getarg_w('s*', w_data).as_str()
         else:
@@ -462,6 +485,7 @@
 
         space = self.space
         self.check_closed()
+        self.check_writable()
         lines = space.fixedview(w_lines)
         for i, w_line in enumerate(lines):
             if not space.isinstance_w(w_line, space.w_str):
diff --git a/pypy/module/_file/test/test_file_extra.py b/pypy/module/_file/test/test_file_extra.py
--- a/pypy/module/_file/test/test_file_extra.py
+++ b/pypy/module/_file/test/test_file_extra.py
@@ -555,15 +555,7 @@
         import errno, sys
         f = open(fn)
         exc = raises(IOError, f.truncate, 3)
-        # CPython explicitly checks the file mode
-        # PyPy relies on the libc to raise the error
-        if '__pypy__' not in sys.builtin_module_names:
-            assert str(exc.value) == "File not open for writing"
-        else:
-            if sys.platform == 'win32':
-                assert exc.value.errno == 5 # ERROR_ACCESS_DENIED
-            else:
-                assert exc.value.errno == errno.EINVAL
+        assert str(exc.value) == "File not open for writing"
         f.close()
 
     def test_readinto(self):


More information about the pypy-commit mailing list