[commit: packages/unix] readdirstream-maybe-patch: Update readDirStream to use Maybe (7c89170)

git at git.haskell.org git at git.haskell.org
Wed Jul 19 22:04:38 UTC 2017


Repository : ssh://git@git.haskell.org/unix

On branch  : readdirstream-maybe-patch
Link       : http://ghc.haskell.org/trac/ghc/changeset/7c89170c19db81b76fbcda8c73e6c6fd9f364f00/unix

>---------------------------------------------------------------

commit 7c89170c19db81b76fbcda8c73e6c6fd9f364f00
Author: Eric Mertens <emertens at galois.com>
Date:   Tue Dec 6 23:22:53 2016 -0800

    Update readDirStream to use Maybe
    
    This patch changes `readDirStream` to signal end of directory with a
    Nothing value. In addition it changes the wrapped readdir function to
    only return -1 in the case of an actual error. This change allows the
    errno handling logic to take advantage of helpers from Foreign.C.Error,
    simplifying the logic.
    
    Fixes #81


>---------------------------------------------------------------

7c89170c19db81b76fbcda8c73e6c6fd9f364f00
 System/Posix/Directory.hsc            | 32 +++++++++++---------------------
 System/Posix/Directory/ByteString.hsc | 32 +++++++++++---------------------
 cbits/HsUnix.c                        |  3 ++-
 changelog.md                          |  4 ++++
 4 files changed, 28 insertions(+), 43 deletions(-)

diff --git a/System/Posix/Directory.hsc b/System/Posix/Directory.hsc
index 10dcbb4..7273f30 100644
--- a/System/Posix/Directory.hsc
+++ b/System/Posix/Directory.hsc
@@ -87,28 +87,18 @@ foreign import capi unsafe "HsUnix.h opendir"
 -- | @readDirStream dp@ calls @readdir@ to obtain the
 --   next directory entry (@struct dirent@) for the open directory
 --   stream @dp@, and returns the @d_name@ member of that
---  structure.
-readDirStream :: DirStream -> IO FilePath
+--  structure. 'Nothing' is returned upon reaching the end
+--  of the directory.
+readDirStream :: DirStream -> IO (Maybe FilePath)
 readDirStream (DirStream dirp) =
-  alloca $ \ptr_dEnt  -> loop ptr_dEnt
- where
-  loop ptr_dEnt = do
-    resetErrno
-    r <- c_readdir dirp ptr_dEnt
-    if (r == 0)
-         then do dEnt <- peek ptr_dEnt
-                 if (dEnt == nullPtr)
-                    then return []
-                    else do
-                     entry <- (d_name dEnt >>= peekFilePath)
-                     c_freeDirEnt dEnt
-                     return entry
-         else do errno <- getErrno
-                 if (errno == eINTR) then loop ptr_dEnt else do
-                 let (Errno eo) = errno
-                 if (eo == 0)
-                    then return []
-                    else throwErrno "readDirStream"
+  alloca $ \ptr_dEnt ->
+    do throwErrnoIfMinus1Retry_ "readdir" (c_readdir dirp ptr_dEnt)
+       dEnt <- peek ptr_dEnt
+       if dEnt == nullPtr
+         then return Nothing
+         else do entry <- peekFilePath =<< d_name dEnt
+                 c_freeDirEnt dEnt
+                 return (Just entry)
 
 -- traversing directories
 foreign import ccall unsafe "__hscore_readdir"
diff --git a/System/Posix/Directory/ByteString.hsc b/System/Posix/Directory/ByteString.hsc
index b5ea462..dc03212 100644
--- a/System/Posix/Directory/ByteString.hsc
+++ b/System/Posix/Directory/ByteString.hsc
@@ -88,28 +88,18 @@ foreign import capi unsafe "HsUnix.h opendir"
 -- | @readDirStream dp@ calls @readdir@ to obtain the
 --   next directory entry (@struct dirent@) for the open directory
 --   stream @dp@, and returns the @d_name@ member of that
---  structure.
-readDirStream :: DirStream -> IO RawFilePath
+--  structure. 'Nothing' is returned upon reaching the end
+--  of the directory.
+readDirStream :: DirStream -> IO (Maybe RawFilePath)
 readDirStream (DirStream dirp) =
-  alloca $ \ptr_dEnt  -> loop ptr_dEnt
- where
-  loop ptr_dEnt = do
-    resetErrno
-    r <- c_readdir dirp ptr_dEnt
-    if (r == 0)
-         then do dEnt <- peek ptr_dEnt
-                 if (dEnt == nullPtr)
-                    then return BC.empty
-                    else do
-                     entry <- (d_name dEnt >>= peekFilePath)
-                     c_freeDirEnt dEnt
-                     return entry
-         else do errno <- getErrno
-                 if (errno == eINTR) then loop ptr_dEnt else do
-                 let (Errno eo) = errno
-                 if (eo == 0)
-                    then return BC.empty
-                    else throwErrno "readDirStream"
+  alloca $ \ptr_dEnt ->
+    do throwErrnoIfMinus1Retry_ "readdir" (c_readdir dirp ptr_dEnt)
+       dEnt <- peek ptr_dEnt
+       if dEnt == nullPtr
+         then return Nothing
+         else do entry <- peekFilePath =<< d_name dEnt
+                 c_freeDirEnt dEnt
+                 return (Just entry)
 
 -- traversing directories
 foreign import ccall unsafe "__hscore_readdir"
diff --git a/cbits/HsUnix.c b/cbits/HsUnix.c
index 7c72a34..5ba9fdc 100644
--- a/cbits/HsUnix.c
+++ b/cbits/HsUnix.c
@@ -94,8 +94,9 @@ int __hscore_readdir( DIR *dirPtr, struct dirent **pDirEnt )
     return -1;
   }
 
+  errno = 0;
   *pDirEnt = readdir(dirPtr);
-  if (*pDirEnt == NULL) {
+  if (*pDirEnt == NULL && errno != 0) {
     return -1;
   } else {
     return 0;
diff --git a/changelog.md b/changelog.md
index 4bbeeb3..d1bc198 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,9 @@
 # Changelog for [`unix` package](http://hackage.haskell.org/package/unix)
 
+## next
+
+  * Change type of `readDirStream` and use `Nothing` to signal end of directory
+
 ## 2.7.2.1  *Sep 2016*
 
   * Don't use `readdir_r` if its deprecated.



More information about the ghc-commits mailing list