Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose dirent pointer and added readDirStreamWith #251

Merged
merged 15 commits into from
Jun 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 8 additions & 36 deletions System/Posix/Directory.hsc
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ module System.Posix.Directory (
changeWorkingDirectoryFd,
) where

import Control.Monad ((>=>))
import Data.Maybe
import System.Posix.Error
import System.Posix.Types
@@ -84,50 +85,21 @@ 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.
-- structure.
--
-- Note that this function returns an empty filepath if the end of the
-- directory stream is reached. For a safer alternative use
-- 'readDirStreamMaybe'.
-- Note that this function returns an empty filepath if the end of the
-- directory stream is reached. For a safer alternative use
-- 'readDirStreamMaybe'.
readDirStream :: DirStream -> IO FilePath
readDirStream = fmap (fromMaybe "") . readDirStreamMaybe

-- | @readDirStreamMaybe dp@ calls @readdir@ to obtain the
-- next directory entry (@struct dirent@) for the open directory
-- stream @dp@. It returns the @d_name@ member of that
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
-- the end of the directory stream was reached.
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
-- the end of the directory stream was reached.
readDirStreamMaybe :: DirStream -> IO (Maybe FilePath)
readDirStreamMaybe (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 Nothing
else do
entry <- (d_name dEnt >>= peekFilePath)
c_freeDirEnt dEnt
return $ Just entry
else do errno <- getErrno
if (errno == eINTR) then loop ptr_dEnt else do
let (Errno eo) = errno
if (eo == 0)
then return Nothing
else throwErrno "readDirStream"

-- traversing directories
foreign import ccall unsafe "__hscore_readdir"
c_readdir :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt

foreign import ccall unsafe "__hscore_free_dirent"
c_freeDirEnt :: Ptr CDirent -> IO ()

foreign import ccall unsafe "__hscore_d_name"
d_name :: Ptr CDirent -> IO CString
readDirStreamMaybe = readDirStreamWith (dirEntName >=> peekFilePath)


-- | @getWorkingDirectory@ calls @getcwd@ to obtain the name
46 changes: 9 additions & 37 deletions System/Posix/Directory/ByteString.hsc
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ module System.Posix.Directory.ByteString (
changeWorkingDirectoryFd,
) where

import Control.Monad ((>=>))
import Data.Maybe
import System.Posix.Types
import Foreign
@@ -60,7 +61,7 @@ import System.Posix.ByteString.FilePath

-- | @createDirectory dir mode@ calls @mkdir@ to
-- create a new directory, @dir@, with permissions based on
-- @mode@.
-- @mode@.
createDirectory :: RawFilePath -> FileMode -> IO ()
createDirectory name mode =
withFilePath name $ \s ->
@@ -85,50 +86,21 @@ 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.
-- structure.
--
-- Note that this function returns an empty filepath if the end of the
-- directory stream is reached. For a safer alternative use
-- 'readDirStreamMaybe'.
-- Note that this function returns an empty filepath if the end of the
-- directory stream is reached. For a safer alternative use
-- 'readDirStreamMaybe'.
readDirStream :: DirStream -> IO RawFilePath
readDirStream = fmap (fromMaybe BC.empty) . readDirStreamMaybe

-- | @readDirStreamMaybe dp@ calls @readdir@ to obtain the
-- next directory entry (@struct dirent@) for the open directory
-- stream @dp@. It returns the @d_name@ member of that
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
-- the end of the directory stream was reached.
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
-- the end of the directory stream was reached.
readDirStreamMaybe :: DirStream -> IO (Maybe RawFilePath)
readDirStreamMaybe (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 Nothing
else do
entry <- (d_name dEnt >>= peekFilePath)
c_freeDirEnt dEnt
return $ Just entry
else do errno <- getErrno
if (errno == eINTR) then loop ptr_dEnt else do
let (Errno eo) = errno
if (eo == 0)
then return Nothing
else throwErrno "readDirStream"

-- traversing directories
foreign import ccall unsafe "__hscore_readdir"
c_readdir :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt

foreign import ccall unsafe "__hscore_free_dirent"
c_freeDirEnt :: Ptr CDirent -> IO ()

foreign import ccall unsafe "__hscore_d_name"
d_name :: Ptr CDirent -> IO CString
readDirStreamMaybe = readDirStreamWith (dirEntName >=> peekFilePath)


-- | @getWorkingDirectory@ calls @getcwd@ to obtain the name
Loading