Commit bbdb17d1 authored by Benjamin Peterson's avatar Benjamin Peterson Committed by GitHub

return the new file descriptor from os.dup2 (closes bpo-32441) (#5041)

parent 03220fdb
...@@ -735,13 +735,17 @@ as internal buffering of data. ...@@ -735,13 +735,17 @@ as internal buffering of data.
.. function:: dup2(fd, fd2, inheritable=True) .. function:: dup2(fd, fd2, inheritable=True)
Duplicate file descriptor *fd* to *fd2*, closing the latter first if necessary. Duplicate file descriptor *fd* to *fd2*, closing the latter first if
The file descriptor *fd2* is :ref:`inheritable <fd_inheritance>` by default, necessary. Return *fd2*. The new file descriptor is :ref:`inheritable
or non-inheritable if *inheritable* is ``False``. <fd_inheritance>` by default or non-inheritable if *inheritable*
is ``False``.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Add the optional *inheritable* parameter. Add the optional *inheritable* parameter.
.. versionchanged:: 3.7
Return *fd2* on success. Previously, ``None`` was always returned.
.. function:: fchmod(fd, mode) .. function:: fchmod(fd, mode)
......
...@@ -3079,19 +3079,15 @@ class FDInheritanceTests(unittest.TestCase): ...@@ -3079,19 +3079,15 @@ class FDInheritanceTests(unittest.TestCase):
# inheritable by default # inheritable by default
fd2 = os.open(__file__, os.O_RDONLY) fd2 = os.open(__file__, os.O_RDONLY)
try: self.addCleanup(os.close, fd2)
os.dup2(fd, fd2) self.assertEqual(os.dup2(fd, fd2), fd2)
self.assertEqual(os.get_inheritable(fd2), True) self.assertTrue(os.get_inheritable(fd2))
finally:
os.close(fd2)
# force non-inheritable # force non-inheritable
fd3 = os.open(__file__, os.O_RDONLY) fd3 = os.open(__file__, os.O_RDONLY)
try: self.addCleanup(os.close, fd3)
os.dup2(fd, fd3, inheritable=False) self.assertEqual(os.dup2(fd, fd3, inheritable=False), fd3)
self.assertEqual(os.get_inheritable(fd3), False) self.assertFalse(os.get_inheritable(fd3))
finally:
os.close(fd3)
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()") @unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
def test_openpty(self): def test_openpty(self):
......
Return the new file descriptor (i.e., the second argument) from ``os.dup2``.
Previously, ``None`` was always returned.
...@@ -3486,7 +3486,7 @@ PyDoc_STRVAR(os_dup2__doc__, ...@@ -3486,7 +3486,7 @@ PyDoc_STRVAR(os_dup2__doc__,
#define OS_DUP2_METHODDEF \ #define OS_DUP2_METHODDEF \
{"dup2", (PyCFunction)os_dup2, METH_FASTCALL|METH_KEYWORDS, os_dup2__doc__}, {"dup2", (PyCFunction)os_dup2, METH_FASTCALL|METH_KEYWORDS, os_dup2__doc__},
static PyObject * static int
os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable); os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable);
static PyObject * static PyObject *
...@@ -3498,12 +3498,17 @@ os_dup2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwn ...@@ -3498,12 +3498,17 @@ os_dup2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwn
int fd; int fd;
int fd2; int fd2;
int inheritable = 1; int inheritable = 1;
int _return_value;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&fd, &fd2, &inheritable)) { &fd, &fd2, &inheritable)) {
goto exit; goto exit;
} }
return_value = os_dup2_impl(module, fd, fd2, inheritable); _return_value = os_dup2_impl(module, fd, fd2, inheritable);
if ((_return_value == -1) && PyErr_Occurred()) {
goto exit;
}
return_value = PyLong_FromLong((long)_return_value);
exit: exit:
return return_value; return return_value;
...@@ -6405,4 +6410,4 @@ exit: ...@@ -6405,4 +6410,4 @@ exit:
#ifndef OS_GETRANDOM_METHODDEF #ifndef OS_GETRANDOM_METHODDEF
#define OS_GETRANDOM_METHODDEF #define OS_GETRANDOM_METHODDEF
#endif /* !defined(OS_GETRANDOM_METHODDEF) */ #endif /* !defined(OS_GETRANDOM_METHODDEF) */
/*[clinic end generated code: output=b6ade5f170d5a431 input=a9049054013a1b77]*/ /*[clinic end generated code: output=6345053cd5992caf input=a9049054013a1b77]*/
...@@ -7770,7 +7770,7 @@ os_dup_impl(PyObject *module, int fd) ...@@ -7770,7 +7770,7 @@ os_dup_impl(PyObject *module, int fd)
/*[clinic input] /*[clinic input]
os.dup2 os.dup2 -> int
fd: int fd: int
fd2: int fd2: int
inheritable: bool=True inheritable: bool=True
...@@ -7778,9 +7778,9 @@ os.dup2 ...@@ -7778,9 +7778,9 @@ os.dup2
Duplicate file descriptor. Duplicate file descriptor.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static int
os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
/*[clinic end generated code: output=db832a2d872ccc5f input=76e96f511be0352f]*/ /*[clinic end generated code: output=bc059d34a73404d1 input=c3cddda8922b038d]*/
{ {
int res; int res;
#if defined(HAVE_DUP3) && \ #if defined(HAVE_DUP3) && \
...@@ -7789,8 +7789,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) ...@@ -7789,8 +7789,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
int dup3_works = -1; int dup3_works = -1;
#endif #endif
if (fd < 0 || fd2 < 0) if (fd < 0 || fd2 < 0) {
return posix_error(); posix_error();
return -1;
}
/* dup2() can fail with EINTR if the target FD is already open, because it /* dup2() can fail with EINTR if the target FD is already open, because it
* then has to be closed. See os_close_impl() for why we don't handle EINTR * then has to be closed. See os_close_impl() for why we don't handle EINTR
...@@ -7802,13 +7804,16 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) ...@@ -7802,13 +7804,16 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
res = dup2(fd, fd2); res = dup2(fd, fd2);
_Py_END_SUPPRESS_IPH _Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res < 0) if (res < 0) {
return posix_error(); posix_error();
return -1;
}
res = fd2; // msvcrt dup2 returns 0 on success.
/* Character files like console cannot be make non-inheritable */ /* Character files like console cannot be make non-inheritable */
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) { if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
close(fd2); close(fd2);
return NULL; return -1;
} }
#elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC) #elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
...@@ -7818,8 +7823,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) ...@@ -7818,8 +7823,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
else else
res = dup2(fd, fd2); res = dup2(fd, fd2);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res < 0) if (res < 0) {
return posix_error(); posix_error();
return -1;
}
#else #else
...@@ -7831,8 +7838,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) ...@@ -7831,8 +7838,10 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
if (res < 0) { if (res < 0) {
if (dup3_works == -1) if (dup3_works == -1)
dup3_works = (errno != ENOSYS); dup3_works = (errno != ENOSYS);
if (dup3_works) if (dup3_works) {
return posix_error(); posix_error();
return -1;
}
} }
} }
...@@ -7842,12 +7851,14 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) ...@@ -7842,12 +7851,14 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
res = dup2(fd, fd2); res = dup2(fd, fd2);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (res < 0) if (res < 0) {
return posix_error(); posix_error();
return -1;
}
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) { if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
close(fd2); close(fd2);
return NULL; return -1;
} }
#ifdef HAVE_DUP3 #ifdef HAVE_DUP3
} }
...@@ -7855,7 +7866,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) ...@@ -7855,7 +7866,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
#endif #endif
Py_RETURN_NONE; return res;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment