    {-# LINE 1 "libraries/unix/System/Posix/Directory/PosixPath.hsc" #-}
    {-# LANGUAGE CApiFFI #-}
    {-# LANGUAGE NondecreasingIndentation #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  System.Posix.Directory.PosixPath
    -- Copyright   :  (c) The University of Glasgow 2002
    -- License     :  BSD-style (see the file libraries/base/LICENSE)
    --
    -- Maintainer  :  libraries@haskell.org
    -- Stability   :  provisional
    -- Portability :  non-portable (requires POSIX)
    --
    -- PosixPath based POSIX directory support
    --
    -----------------------------------------------------------------------------

    -- hack copied from System.Posix.Files

    {-# LINE 24 "libraries/unix/System/Posix/Directory/PosixPath.hsc" #-}

    module System.Posix.Directory.PosixPath (
       -- * Creating and removing directories
       createDirectory, removeDirectory,

       -- * Reading directories
       DirStream,
       openDirStream,
       readDirStream,
       rewindDirStream,
       closeDirStream,
       DirStreamOffset,

    {-# LINE 37 "libraries/unix/System/Posix/Directory/PosixPath.hsc" #-}
       tellDirStream,

    {-# LINE 39 "libraries/unix/System/Posix/Directory/PosixPath.hsc" #-}

    {-# LINE 40 "libraries/unix/System/Posix/Directory/PosixPath.hsc" #-}
       seekDirStream,

    {-# LINE 42 "libraries/unix/System/Posix/Directory/PosixPath.hsc" #-}

       -- * The working directory
       getWorkingDirectory,
       changeWorkingDirectory,
       changeWorkingDirectoryFd,
      ) where

    import System.Posix.Types
    import Foreign
    import Foreign.C

    import System.OsPath.Types
    import System.Posix.Directory hiding (createDirectory, openDirStream, readDirStream, getWorkingDirectory, changeWorkingDirectory, removeDirectory)
    import qualified System.Posix.Directory.Common as Common
    import System.Posix.PosixPath.FilePath

    -- | @createDirectory dir mode@ calls @mkdir@ to
    --   create a new directory, @dir@, with permissions based on
    --  @mode@.
    createDirectory :: PosixPath -> FileMode -> IO ()
    createDirectory :: PosixPath -> FileMode -> IO ()
    createDirectory PosixPath
    name FileMode
    mode =
      PosixPath -> (CString -> IO ()) -> IO ()
    forall a. PosixPath -> (CString -> IO a) -> IO a
    withFilePath PosixPath
    name ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \CString
    s ->
        String -> PosixPath -> IO CInt -> IO ()
    forall a. (Eq a, Num a) => String -> PosixPath -> IO a -> IO ()
    throwErrnoPathIfMinus1Retry_ String
    "createDirectory" PosixPath
    name (CString -> FileMode -> IO CInt
    c_mkdir CString
    s FileMode
    mode)
        -- POSIX doesn't allow mkdir() to return EINTR, but it does on
        -- OS X (#5184), so we need the Retry variant here.

    foreign import ccall unsafe "mkdir"
      c_mkdir :: CString -> CMode -> IO CInt

    -- | @openDirStream dir@ calls @opendir@ to obtain a
    --   directory stream for @dir@.
    openDirStream :: PosixPath -> IO DirStream
    openDirStream :: PosixPath -> IO DirStream
    openDirStream PosixPath
    name =
      PosixPath -> (CString -> IO DirStream) -> IO DirStream
    forall a. PosixPath -> (CString -> IO a) -> IO a
    withFilePath PosixPath
    name ((CString -> IO DirStream) -> IO DirStream)
    -> (CString -> IO DirStream) -> IO DirStream
    forall a b. (a -> b) -> a -> b
    $ \CString
    s -> do
        dirp <- String -> PosixPath -> IO (Ptr CDir) -> IO (Ptr CDir)
    forall a. String -> PosixPath -> IO (Ptr a) -> IO (Ptr a)
    throwErrnoPathIfNullRetry String
    "openDirStream" PosixPath
    name (IO (Ptr CDir) -> IO (Ptr CDir)) -> IO (Ptr CDir) -> IO (Ptr CDir)
    forall a b. (a -> b) -> a -> b
    $ CString -> IO (Ptr CDir)
    c_opendir CString
    s
        return (Common.DirStream dirp)

    foreign import capi unsafe "HsUnix.h opendir"
       c_opendir :: CString  -> IO (Ptr Common.CDir)

    -- | @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 PosixPath
    readDirStream :: DirStream -> IO PosixPath
    readDirStream (Common.DirStream Ptr CDir
    dirp) = (Ptr (Ptr CDirent) -> IO PosixPath) -> IO PosixPath
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
    alloca ((Ptr (Ptr CDirent) -> IO PosixPath) -> IO PosixPath)
    -> (Ptr (Ptr CDirent) -> IO PosixPath) -> IO PosixPath
    forall a b. (a -> b) -> a -> b
    $ \Ptr (Ptr CDirent)
    ptr_dEnt  -> Ptr (Ptr CDirent) -> IO PosixPath
    loop Ptr (Ptr CDirent)
    ptr_dEnt
     where
      loop :: Ptr (Ptr CDirent) -> IO PosixPath
    loop Ptr (Ptr CDirent)
    ptr_dEnt = do
        IO ()
    resetErrno
        r <- Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt
    c_readdir Ptr CDir
    dirp Ptr (Ptr CDirent)
    ptr_dEnt
        if (r == 0)
             then do dEnt <- peek ptr_dEnt
                     if (dEnt == nullPtr)
                        then return mempty
                        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 mempty
                        else throwErrno "readDirStream"

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

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

    foreign import ccall unsafe "__hscore_d_name"
      d_name :: Ptr Common.CDirent -> IO CString

    -- | @getWorkingDirectory@ calls @getcwd@ to obtain the name
    --   of the current working directory.
    getWorkingDirectory :: IO PosixPath
    getWorkingDirectory :: IO PosixPath
    getWorkingDirectory = Int -> IO PosixPath
    go (Int
    4096)
    {-# LINE 122 "libraries/unix/System/Posix/Directory/PosixPath.hsc" #-}
      where
        go :: Int -> IO PosixPath
    go Int
    bytes = do
            r <- Int -> (CString -> IO (Maybe PosixPath)) -> IO (Maybe PosixPath)
    forall a b. Int -> (Ptr a -> IO b) -> IO b
    allocaBytes Int
    bytes ((CString -> IO (Maybe PosixPath)) -> IO (Maybe PosixPath))
    -> (CString -> IO (Maybe PosixPath)) -> IO (Maybe PosixPath)
    forall a b. (a -> b) -> a -> b
    $ \CString
    buf -> do
                buf' <- CString -> CSize -> IO CString
    c_getcwd CString
    buf (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    bytes)
                if buf' /= nullPtr
                    then do s <- peekFilePath buf
                            return (Just s)
                    else do errno <- getErrno
                            if errno == eRANGE
                                -- we use Nothing to indicate that we should
                                -- try again with a bigger buffer
                                then return Nothing
                                else throwErrno "getWorkingDirectory"
            maybe (go (2 * bytes)) return r

    foreign import ccall unsafe "getcwd"
       c_getcwd   :: Ptr CChar -> CSize -> IO (Ptr CChar)

    -- | @changeWorkingDirectory dir@ calls @chdir@ to change
    --   the current working directory to @dir@.
    changeWorkingDirectory :: PosixPath -> IO ()
    changeWorkingDirectory :: PosixPath -> IO ()
    changeWorkingDirectory PosixPath
    path =
      PosixPath -> (CString -> IO ()) -> IO ()
    forall a. PosixPath -> (CString -> IO a) -> IO a
    withFilePath PosixPath
    path ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \CString
    s ->
         String -> PosixPath -> IO CInt -> IO ()
    forall a. (Eq a, Num a) => String -> PosixPath -> IO a -> IO ()
    throwErrnoPathIfMinus1Retry_ String
    "changeWorkingDirectory" PosixPath
    path (CString -> IO CInt
    c_chdir CString
    s)

    foreign import ccall unsafe "chdir"
       c_chdir :: CString -> IO CInt

    removeDirectory :: PosixPath -> IO ()
    removeDirectory :: PosixPath -> IO ()
    removeDirectory PosixPath
    path =
      PosixPath -> (CString -> IO ()) -> IO ()
    forall a. PosixPath -> (CString -> IO a) -> IO a
    withFilePath PosixPath
    path ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \CString
    s ->
         String -> PosixPath -> IO CInt -> IO ()
    forall a. (Eq a, Num a) => String -> PosixPath -> IO a -> IO ()
    throwErrnoPathIfMinus1Retry_ String
    "removeDirectory" PosixPath
    path (CString -> IO CInt
    c_rmdir CString
    s)

    foreign import ccall unsafe "rmdir"
       c_rmdir :: CString -> IO CInt