]> granicus.if.org Git - python/commitdiff
when an exception is raised in fdopen, never close the fd (changing on my mind on...
authorBenjamin Peterson <benjamin@python.org>
Mon, 14 Apr 2014 23:45:46 +0000 (19:45 -0400)
committerBenjamin Peterson <benjamin@python.org>
Mon, 14 Apr 2014 23:45:46 +0000 (19:45 -0400)
Doc/library/os.rst
Lib/test/test_posix.py
Misc/NEWS
Modules/posixmodule.c

index 195a4a80fcb83b83411248bc3ede35581a820f95..2149ae5fa94c88b0c5720e3adf3576d44bf6df39 100644 (file)
@@ -465,7 +465,7 @@ These functions create new file objects. (See also :func:`open`.)
    Return an open file object connected to the file descriptor *fd*.  The *mode*
    and *bufsize* arguments have the same meaning as the corresponding arguments
    to the built-in :func:`open` function.  If :func:`fdopen` raises an
-   exception, it closes *fd*.
+   exception, it leaves *fd* untouched (unclosed).
 
    Availability: Unix, Windows.
 
index 243fd5d6ed13729a573e6ddf98e45d8661132381..d63156286ac3a9943161eca2b96e1fe635f5de96 100644 (file)
@@ -196,7 +196,7 @@ class PosixTester(unittest.TestCase):
 
         fd = os.open(test_support.TESTFN, os.O_RDONLY)
         self.assertRaises(OSError, posix.fdopen, fd, 'w')
-        self.assertRaises(OSError, os.close, fd) # fd should be closed.
+        os.close(fd) # fd should not be closed.
 
     @unittest.skipUnless(hasattr(posix, 'O_EXLOCK'),
                          'test needs posix.O_EXLOCK')
index f6a2c65e9121483e7b50549b7b9c7fb9e5b81d56..94d363807ed4272cba87939fa59918c2f07a274c 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -51,7 +51,7 @@ Library
 
 - Issue #21172: isinstance check relaxed from dict to collections.Mapping.
 
-- Issue #21191: In os.fdopen, alwyas close the file descriptor when an exception
+- Issue #21191: In os.fdopen, never close the file descriptor when an exception
   happens.
 
 - Issue #21149: Improved thread-safety in logging cleanup during interpreter
index 168f7f491731acaf86abf6979d1c6da910751948..7a5ef1cab3045cd4c467ca7bc8724c2000645b76 100644 (file)
@@ -6841,19 +6841,37 @@ posix_fdopen(PyObject *self, PyObject *args)
     /* Sanitize mode.  See fileobject.c */
     mode = PyMem_MALLOC(strlen(orgmode)+3);
     if (!mode) {
-        close(fd);
         PyErr_NoMemory();
         return NULL;
     }
     strcpy(mode, orgmode);
     if (_PyFile_SanitizeMode(mode)) {
-        close(fd);
         PyMem_FREE(mode);
         return NULL;
     }
     if (!_PyVerify_fd(fd)) {
-        posix_error();
-        close(fd);
+        PyMem_FREE(mode);
+        return posix_error();
+    }
+#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
+    {
+        struct stat buf;
+        if (fstat(fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
+            PyMem_FREE(mode);
+            char *msg = strerror(EISDIR);
+            PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(isO)",
+                                                  EISDIR, msg, "<fdopen>");
+            PyErr_SetObject(PyExc_IOError, exc);
+            Py_XDECREF(exc);
+            return NULL;
+        }
+    }
+#endif
+    /* The dummy filename used here must be kept in sync with the value
+       tested against in gzip.GzipFile.__init__() - see issue #13781. */
+    f = PyFile_FromFile(NULL, "<fdopen>", orgmode, fclose);
+    if (f == NULL) {
+        PyMem_FREE(mode);
         return NULL;
     }
     Py_BEGIN_ALLOW_THREADS
@@ -6876,16 +6894,11 @@ posix_fdopen(PyObject *self, PyObject *args)
 #endif
     Py_END_ALLOW_THREADS
     PyMem_FREE(mode);
-    if (fp == NULL) {
-        posix_error();
-        close(fd);
-        return NULL;
-    }
-    /* The dummy filename used here must be kept in sync with the value
-       tested against in gzip.GzipFile.__init__() - see issue #13781. */
-    f = PyFile_FromFile(fp, "<fdopen>", orgmode, fclose);
-    if (f != NULL)
-        PyFile_SetBufSize(f, bufsize);
+    if (fp == NULL)
+        return posix_error();
+    /* We now know we will succeed, so initialize the file object. */
+    ((PyFileObject *)f)->f_fp = fp;
+    PyFile_SetBufSize(f, bufsize);
     return f;
 }