Issue #10755: Add the posix.fdlistdir() function. Patch by Ross Lagerwall.
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index 67034ea..692aa9c 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -733,6 +733,16 @@
This function is not available on MacOS.
+.. function:: fdlistdir(fd)
+
+ Like :func:`listdir`, but uses a file descriptor instead and always returns
+ strings. After execution of this function, *fd* will be closed.
+
+ Availability: Unix.
+
+ .. versionadded:: 3.3
+
+
.. function:: fpathconf(fd, name)
Return system configuration information relevant to an open file. *name*
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 2fb8200..23c2100 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -285,6 +285,18 @@
if hasattr(posix, 'listdir'):
self.assertTrue(support.TESTFN in posix.listdir())
+ @unittest.skipUnless(hasattr(posix, 'fdlistdir'), "test needs posix.fdlistdir()")
+ def test_fdlistdir(self):
+ f = posix.open(posix.getcwd(), posix.O_RDONLY)
+ self.assertEqual(
+ sorted(posix.listdir('.')),
+ sorted(posix.fdlistdir(f))
+ )
+ # Check the fd was closed by fdlistdir
+ with self.assertRaises(OSError) as ctx:
+ posix.close(f)
+ self.assertEqual(ctx.exception.errno, errno.EBADF)
+
def test_access(self):
if hasattr(posix, 'access'):
self.assertTrue(posix.access(support.TESTFN, os.R_OK))
diff --git a/Misc/NEWS b/Misc/NEWS
index 1630ab2..d3d813c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -35,6 +35,8 @@
Library
-------
+- Issue #10755: Add the posix.fdlistdir() function. Patch by Ross Lagerwall.
+
- Issue #4761: Add the *at() family of functions (openat(), etc.) to the posix
module. Patch by Ross Lagerwall.
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 1281af7..077343e 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -2678,6 +2678,76 @@
#endif /* which OS */
} /* end of posix_listdir */
+#ifdef HAVE_FDOPENDIR
+PyDoc_STRVAR(posix_fdlistdir__doc__,
+"fdlistdir(fd) -> list_of_strings\n\n\
+Like listdir(), but uses a file descriptor instead.\n\
+After succesful execution of this function, fd will be closed.");
+
+static PyObject *
+posix_fdlistdir(PyObject *self, PyObject *args)
+{
+ PyObject *d, *v;
+ DIR *dirp;
+ struct dirent *ep;
+ int fd;
+
+ errno = 0;
+ if (!PyArg_ParseTuple(args, "i:fdlistdir", &fd))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ dirp = fdopendir(fd);
+ Py_END_ALLOW_THREADS
+ if (dirp == NULL) {
+ close(fd);
+ return posix_error();
+ }
+ if ((d = PyList_New(0)) == NULL) {
+ Py_BEGIN_ALLOW_THREADS
+ closedir(dirp);
+ Py_END_ALLOW_THREADS
+ return NULL;
+ }
+ for (;;) {
+ errno = 0;
+ Py_BEGIN_ALLOW_THREADS
+ ep = readdir(dirp);
+ Py_END_ALLOW_THREADS
+ if (ep == NULL) {
+ if (errno == 0) {
+ break;
+ } else {
+ Py_BEGIN_ALLOW_THREADS
+ closedir(dirp);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(d);
+ return posix_error();
+ }
+ }
+ if (ep->d_name[0] == '.' &&
+ (NAMLEN(ep) == 1 ||
+ (ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
+ continue;
+ v = PyUnicode_DecodeFSDefaultAndSize(ep->d_name, NAMLEN(ep));
+ if (v == NULL) {
+ Py_CLEAR(d);
+ break;
+ }
+ if (PyList_Append(d, v) != 0) {
+ Py_DECREF(v);
+ Py_CLEAR(d);
+ break;
+ }
+ Py_DECREF(v);
+ }
+ Py_BEGIN_ALLOW_THREADS
+ closedir(dirp);
+ Py_END_ALLOW_THREADS
+
+ return d;
+}
+#endif
+
#ifdef MS_WINDOWS
/* A helper function for abspath on win32 */
static PyObject *
@@ -8599,6 +8669,9 @@
{"link", posix_link, METH_VARARGS, posix_link__doc__},
#endif /* HAVE_LINK */
{"listdir", posix_listdir, METH_VARARGS, posix_listdir__doc__},
+#ifdef HAVE_FDOPENDIR
+ {"fdlistdir", posix_fdlistdir, METH_VARARGS, posix_fdlistdir__doc__},
+#endif
{"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__},
{"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__},
#ifdef HAVE_NICE
diff --git a/configure b/configure
index 6bbda01..74d1ed4 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.in Revision: 88608 .
+# From configure.in Revision: 88624 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.65 for python 3.3.
#
@@ -9311,8 +9311,8 @@
# checks for library functions
for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
- clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat fork \
- fpathconf fstatat ftime ftruncate futimesat \
+ clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat \
+ fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
initgroups kill killpg lchmod lchown linkat lstat mbrtowc mkdirat mkfifo \
diff --git a/configure.in b/configure.in
index c0f7ab8..43e2159 100644
--- a/configure.in
+++ b/configure.in
@@ -2534,8 +2534,8 @@
# checks for library functions
AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
- clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat fork \
- fpathconf fstatat ftime ftruncate futimesat \
+ clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat \
+ fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
initgroups kill killpg lchmod lchown linkat lstat mbrtowc mkdirat mkfifo \
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 1d6912d..771cd38 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -229,6 +229,9 @@
/* Define if you have the 'fdatasync' function. */
#undef HAVE_FDATASYNC
+/* Define to 1 if you have the `fdopendir' function. */
+#undef HAVE_FDOPENDIR
+
/* Define to 1 if you have the `finite' function. */
#undef HAVE_FINITE
@@ -533,6 +536,9 @@
/* Define if the OS supports pipe2() */
#undef HAVE_PIPE2
+/* Define if the OS supports pipe2() */
+#undef HAVE_PIPE2
+
/* Define to 1 if you have the `plock' function. */
#undef HAVE_PLOCK