Author: Ronan Lamy <[email protected]>
Branch: rposix-for-3
Changeset: r83471:42e156eb8e2c
Date: 2016-03-31 18:12 +0100
http://bitbucket.org/pypy/pypy/changeset/42e156eb8e2c/

Log:    Add rposix.fdlistdir(): variant of rposix.listdir() using
        fdopendir()

diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -603,14 +603,44 @@
     config = rffi_platform.configure(CConfig)
     DIRENT = config['DIRENT']
     DIRENTP = lltype.Ptr(DIRENT)
-    c_opendir = external('opendir', [rffi.CCHARP], DIRP,
-                         save_err=rffi.RFFI_SAVE_ERRNO)
+    c_opendir = external('opendir',
+        [rffi.CCHARP], DIRP, save_err=rffi.RFFI_SAVE_ERRNO)
+    c_fdopendir = external('fdopendir',
+        [rffi.INT], DIRP, save_err=rffi.RFFI_SAVE_ERRNO)
     # XXX macro=True is hack to make sure we get the correct kind of
     # dirent struct (which depends on defines)
     c_readdir = external('readdir', [DIRP], DIRENTP,
                          macro=True, save_err=rffi.RFFI_FULL_ERRNO_ZERO)
     c_closedir = external('closedir', [DIRP], rffi.INT)
 
+def _listdir(dirp):
+    result = []
+    while True:
+        direntp = c_readdir(dirp)
+        if not direntp:
+            error = get_saved_errno()
+            break
+        namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
+        name = rffi.charp2str(namep)
+        if name != '.' and name != '..':
+            result.append(name)
+    c_closedir(dirp)
+    if error:
+        raise OSError(error, "readdir failed")
+    return result
+
+def fdlistdir(dirfd):
+    """
+    Like listdir(), except that the directory is specified as an open
+    file descriptor.
+
+    Note: fdlistdir() closes the file descriptor.
+    """
+    dirp = c_fdopendir(dirfd)
+    if not dirp:
+        raise OSError(get_saved_errno(), "opendir failed")
+    return _listdir(dirp)
+
 @replace_os_function('listdir')
 @specialize.argtype(0)
 def listdir(path):
@@ -619,20 +649,7 @@
         dirp = c_opendir(path)
         if not dirp:
             raise OSError(get_saved_errno(), "opendir failed")
-        result = []
-        while True:
-            direntp = c_readdir(dirp)
-            if not direntp:
-                error = get_saved_errno()
-                break
-            namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
-            name = rffi.charp2str(namep)
-            if name != '.' and name != '..':
-                result.append(name)
-        c_closedir(dirp)
-        if error:
-            raise OSError(error, "readdir failed")
-        return result
+        return _listdir(dirp)
     else:  # _WIN32 case
         traits = _preferred_traits(path)
         win32traits = make_win32_traits(traits)
diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py
--- a/rpython/rlib/test/test_rposix.py
+++ b/rpython/rlib/test/test_rposix.py
@@ -528,6 +528,14 @@
             os.open(u'/tmp/t', 0, 0)
         compile(f, ())
 
+
+def test_fdlistdir(tmpdir):
+    tmpdir.join('file').write('text')
+    dirfd = os.open(str(tmpdir), os.O_RDONLY)
+    result = rposix.fdlistdir(dirfd)
+    # Note: fdlistdir() always closes dirfd
+    assert result == ['file']
+
 def test_symlinkat(tmpdir):
     tmpdir.join('file').write('text')
     dirfd = os.open(str(tmpdir), os.O_RDONLY)
@@ -537,7 +545,6 @@
     finally:
         os.close(dirfd)
 
-
 def test_renameat(tmpdir):
     tmpdir.join('file').write('text')
     dirfd = os.open(str(tmpdir), os.O_RDONLY)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to