Merged revisions 77989 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r77989 | antoine.pitrou | 2010-02-05 18:05:54 +0100 (ven., 05 févr. 2010) | 6 lines

  Issue #5677: Explicitly forbid write operations on read-only file objects,
  and read operations on write-only file objects.  On Windows, the system C
  library would return a bogus result; on Solaris, it was possible to crash
  the interpreter.  Patch by Stefan Krah.
........
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index e01f38e..52d8120 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -173,6 +173,13 @@
 	f->f_encoding = Py_None;
 	Py_INCREF(Py_None);
 	f->f_errors = Py_None;
+	f->readable = f->writable = 0;
+	if (strchr(mode, 'r') != NULL || f->f_univ_newline)
+		f->readable = 1;
+	if (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL)
+		f->writable = 1;
+	if (strchr(mode, '+') != NULL)
+		f->readable = f->writable = 1;
 
 	if (f->f_mode == NULL)
 		return NULL;
@@ -487,6 +494,13 @@
 	return NULL;
 }
 
+static PyObject *
+err_mode(char *action)
+{
+        PyErr_Format(PyExc_IOError, "File not open for %s", action);
+        return NULL;
+}
+
 /* Refuse regular file I/O if there's data in the iteration-buffer.
  * Mixing them would cause data to arrive out of order, as the read*
  * methods don't use the iteration buffer. */
@@ -701,6 +715,8 @@
 
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->writable)
+		return err_mode("writing");
 	if (!PyArg_UnpackTuple(args, "truncate", 0, 1, &newsizeobj))
 		return NULL;
 
@@ -949,6 +965,8 @@
 
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->readable)
+		return err_mode("reading");
 	/* refuse to mix with f.next() */
 	if (f->f_buf != NULL &&
 	    (f->f_bufend - f->f_bufptr) > 0 &&
@@ -1018,6 +1036,8 @@
 
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->readable)
+		return err_mode("reading");
 	/* refuse to mix with f.next() */
 	if (f->f_buf != NULL &&
 	    (f->f_bufend - f->f_bufptr) > 0 &&
@@ -1389,6 +1409,8 @@
 		PyFileObject *fo = (PyFileObject *)f;
 		if (fo->f_fp == NULL)
 			return err_closed();
+		if (!fo->readable)
+			return err_mode("reading");
 		/* refuse to mix with f.next() */
 		if (fo->f_buf != NULL &&
 		    (fo->f_bufend - fo->f_bufptr) > 0 &&
@@ -1477,6 +1499,8 @@
 
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->readable)
+		return err_mode("reading");
 	/* refuse to mix with f.next() */
 	if (f->f_buf != NULL &&
 	    (f->f_bufend - f->f_bufptr) > 0 &&
@@ -1510,6 +1534,8 @@
 
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->readable)
+		return err_mode("reading");
 	/* refuse to mix with f.next() */
 	if (f->f_buf != NULL &&
 	    (f->f_bufend - f->f_bufptr) > 0 &&
@@ -1628,6 +1654,8 @@
 	Py_ssize_t n, n2;
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->writable)
+		return err_mode("writing");
 	if (f->f_binary) {
 		if (!PyArg_ParseTuple(args, "s*", &pbuf))
 			return NULL;
@@ -1665,6 +1693,8 @@
 	assert(seq != NULL);
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->writable)
+		return err_mode("writing");
 
 	result = NULL;
 	list = NULL;
@@ -2105,6 +2135,8 @@
 
 	if (f->f_fp == NULL)
 		return err_closed();
+	if (!f->readable)
+		return err_mode("reading");
 
 	l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE);
 	if (l == NULL || PyString_GET_SIZE(l) == 0) {