From 8250e23abd12da20fcb03e2314fe6c34b403b534 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Fri, 25 Feb 2011 23:41:16 +0000 Subject: [PATCH] Issue #10755: Add the posix.fdlistdir() function. Patch by Ross Lagerwall. --- Doc/library/os.rst | 10 ++++++ Lib/test/test_posix.py | 12 +++++++ Misc/NEWS | 2 ++ Modules/posixmodule.c | 73 ++++++++++++++++++++++++++++++++++++++++++ configure | 6 ++-- configure.in | 4 +-- pyconfig.h.in | 6 ++++ 7 files changed, 108 insertions(+), 5 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 67034ea574..692aa9c1e9 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -733,6 +733,16 @@ as internal buffering of data. 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 2fb8200e62..23c2100d7a 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -285,6 +285,18 @@ class PosixTester(unittest.TestCase): 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 1630ab2066..d3d813c39c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,8 @@ Core and Builtins 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 1281af78e5..077343e995 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2678,6 +2678,76 @@ posix_listdir(PyObject *self, PyObject *args) #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 @@ static PyMethodDef posix_methods[] = { {"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 6bbda01bd7..74d1ed41d2 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 @@ $as_echo "MACHDEP_OBJS" >&6; } # 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 c0f7ab8b7f..43e215933f 100644 --- a/configure.in +++ b/configure.in @@ -2534,8 +2534,8 @@ AC_MSG_RESULT(MACHDEP_OBJS) # 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 1d6912d196..771cd38291 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 -- 2.50.1