diff --git a/System/Posix/Directory.hsc b/System/Posix/Directory.hsc index 10dcbb4c45d1d83f0217e76e0df4ae65c91f107b..7273f3020f5b67ca0eec4b8ac166fd905a8a4ffb 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 b5ea462c58282788f64cee49042c8d7f4997dcc2..dc032126b86dfe5696dc1064eb1d07cada299511 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 7c72a341cbbdabeea820b4acd375ffbd1da30e17..5ba9fdc60cf44d843f61b0b44ef05390e20578cb 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 4bbeeb374a208bbd6f1a29d6e54a05009d26a876..d1bc198666efa98a9306c2332cd00214e914db89 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.