    {-# LINE 1 "libraries/unix/System/Posix/ByteString/FilePath.hsc" #-}
    {-# LANGUAGE Trustworthy #-}
    {-# LANGUAGE TypeApplications #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  System.Posix.ByteString.FilePath
    -- 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)
    --
    -- Internal stuff: support for ByteString FilePaths
    --
    -----------------------------------------------------------------------------

    module System.Posix.ByteString.FilePath (
         RawFilePath, withFilePath, peekFilePath, peekFilePathLen,
         throwErrnoPathIfMinus1Retry,
         throwErrnoPathIfMinus1Retry_,
         throwErrnoPathIfNullRetry,
         throwErrnoPathIfRetry,
         throwErrnoPath,
         throwErrnoPathIf,
         throwErrnoPathIf_,
         throwErrnoPathIfNull,
         throwErrnoPathIfMinus1,
         throwErrnoPathIfMinus1_,
         throwErrnoTwoPathsIfMinus1_
      ) where

    import Foreign hiding ( void )
    import Foreign.C hiding (
         throwErrnoPath,
         throwErrnoPathIf,
         throwErrnoPathIf_,
         throwErrnoPathIfNull,
         throwErrnoPathIfMinus1,
         throwErrnoPathIfMinus1_ )

    import Control.Monad
    import Control.Exception
    import Data.ByteString.Internal (c_strlen)
    import GHC.Foreign as GHC ( peekCStringLen )
    import GHC.IO.Encoding ( getFileSystemEncoding )
    import GHC.IO.Exception
    import Data.ByteString as B
    import Data.ByteString.Char8 as BC
    import Prelude hiding (FilePath)

    {-# LINE 54 "libraries/unix/System/Posix/ByteString/FilePath.hsc" #-}

    -- | A literal POSIX file path
    type RawFilePath = ByteString

    withFilePath :: RawFilePath -> (CString -> IO a) -> IO a
    withFilePath :: forall a. RawFilePath -> (CString -> IO a) -> IO a
    withFilePath RawFilePath
    path = RawFilePath -> (CString -> IO a) -> IO a
    forall a. RawFilePath -> (CString -> IO a) -> IO a
    useAsCStringSafe RawFilePath
    path

    peekFilePath :: CString -> IO RawFilePath
    peekFilePath :: CString -> IO RawFilePath
    peekFilePath = CString -> IO RawFilePath
    packCString

    peekFilePathLen :: CStringLen -> IO RawFilePath
    peekFilePathLen :: CStringLen -> IO RawFilePath
    peekFilePathLen = CStringLen -> IO RawFilePath
    packCStringLen

    throwErrnoPathIfMinus1Retry :: (Eq a, Num a)
                                => String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfMinus1Retry :: forall a. (Eq a, Num a) => String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfMinus1Retry String
    loc RawFilePath
    path IO a
    f = do
      (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfRetry (a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == -a
    1) String
    loc RawFilePath
    path IO a
    f

    throwErrnoPathIfMinus1Retry_ :: (Eq a, Num a)
                                 => String -> RawFilePath -> IO a -> IO ()
    throwErrnoPathIfMinus1Retry_ :: forall a. (Eq a, Num a) => String -> RawFilePath -> IO a -> IO ()
    throwErrnoPathIfMinus1Retry_ String
    loc RawFilePath
    path IO a
    f =
      IO a -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO a -> IO ()) -> IO a -> IO ()
    forall a b. (a -> b) -> a -> b
    $ (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfRetry (a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == -a
    1) String
    loc RawFilePath
    path IO a
    f

    throwErrnoPathIfNullRetry :: String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
    throwErrnoPathIfNullRetry :: forall a. String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
    throwErrnoPathIfNullRetry String
    loc RawFilePath
    path IO (Ptr a)
    f =
      (Ptr a -> Bool)
    -> String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
    forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfRetry (Ptr a -> Ptr a -> Bool
    forall a. Eq a => a -> a -> Bool
    == Ptr a
    forall a. Ptr a
    nullPtr) String
    loc RawFilePath
    path IO (Ptr a)
    f

    throwErrnoPathIfRetry :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfRetry :: forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfRetry a -> Bool
    pr String
    loc RawFilePath
    rpath IO a
    f =
      do
        res <- IO a
    f
        if pr res
          then do
            err <- getErrno
            if err == eINTR
              then throwErrnoPathIfRetry pr loc rpath f
              else throwErrnoPath loc rpath
          else return res

    -- | as 'throwErrno', but exceptions include the given path when appropriate.
    --
    throwErrnoPath :: String -> RawFilePath -> IO a
    throwErrnoPath :: forall a. String -> RawFilePath -> IO a
    throwErrnoPath String
    loc RawFilePath
    path =
      do
        errno <- IO Errno
    getErrno
        path' <- either (const (BC.unpack path)) id <$> try @IOException (decodeWithBasePosix path)
        ioError (errnoToIOError loc errno Nothing (Just path'))

    -- | as 'throwErrnoIf', but exceptions include the given path when
    --   appropriate.
    --
    throwErrnoPathIf :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIf :: forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIf a -> Bool
    cond String
    loc RawFilePath
    path IO a
    f =
      do
        res <- IO a
    f
        if cond res then throwErrnoPath loc path else return res

    -- | as 'throwErrnoIf_', but exceptions include the given path when
    --   appropriate.
    --
    throwErrnoPathIf_ :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO ()
    throwErrnoPathIf_ :: forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO ()
    throwErrnoPathIf_ a -> Bool
    cond String
    loc RawFilePath
    path IO a
    f  = IO a -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO a -> IO ()) -> IO a -> IO ()
    forall a b. (a -> b) -> a -> b
    $ (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIf a -> Bool
    cond String
    loc RawFilePath
    path IO a
    f

    -- | as 'throwErrnoIfNull', but exceptions include the given path when
    --   appropriate.
    --
    throwErrnoPathIfNull :: String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
    throwErrnoPathIfNull :: forall a. String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
    throwErrnoPathIfNull  = (Ptr a -> Bool)
    -> String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
    forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIf (Ptr a -> Ptr a -> Bool
    forall a. Eq a => a -> a -> Bool
    == Ptr a
    forall a. Ptr a
    nullPtr)

    -- | as 'throwErrnoIfMinus1', but exceptions include the given path when
    --   appropriate.
    --
    throwErrnoPathIfMinus1 :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfMinus1 :: forall a. (Eq a, Num a) => String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIfMinus1 = (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
    throwErrnoPathIf (a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == -a
    1)

    -- | as 'throwErrnoIfMinus1_', but exceptions include the given path when
    --   appropriate.
    --
    throwErrnoPathIfMinus1_ :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO ()
    throwErrnoPathIfMinus1_ :: forall a. (Eq a, Num a) => String -> RawFilePath -> IO a -> IO ()
    throwErrnoPathIfMinus1_  = (a -> Bool) -> String -> RawFilePath -> IO a -> IO ()
    forall a. (a -> Bool) -> String -> RawFilePath -> IO a -> IO ()
    throwErrnoPathIf_ (a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == -a
    1)

    -- | as 'throwErrnoTwoPathsIfMinus1_', but exceptions include two paths when appropriate.
    --
    throwErrnoTwoPathsIfMinus1_ :: (Eq a, Num a) => String -> RawFilePath -> RawFilePath -> IO a -> IO ()
    throwErrnoTwoPathsIfMinus1_ :: forall a.
    (Eq a, Num a) =>
    String -> RawFilePath -> RawFilePath -> IO a -> IO ()
    throwErrnoTwoPathsIfMinus1_  String
    loc RawFilePath
    path1 RawFilePath
    path2 IO a
    action = do
        path1' <- (IOException -> String)
    -> (String -> String) -> Either IOException String -> String
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (String -> IOException -> String
    forall a b. a -> b -> a
    const (RawFilePath -> String
    BC.unpack RawFilePath
    path1)) String -> String
    forall a. a -> a
    id (Either IOException String -> String)
    -> IO (Either IOException String) -> IO String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> forall e a. Exception e => IO a -> IO (Either e a)
    try @IOException (RawFilePath -> IO String
    decodeWithBasePosix RawFilePath
    path1)
        path2' <- either (const (BC.unpack path2)) id <$> try @IOException (decodeWithBasePosix path2)
        throwErrnoIfMinus1_ (loc <> " '" <> path1' <> "' to '" <> path2' <> "'") action

    -- | This mimics the filepath decoder base uses on unix,
    -- with the small distinction that we're not truncating at NUL bytes (because we're not at
    -- the outer FFI layer).
    decodeWithBasePosix :: RawFilePath -> IO String
    decodeWithBasePosix :: RawFilePath -> IO String
    decodeWithBasePosix RawFilePath
    ba = RawFilePath -> (CStringLen -> IO String) -> IO String
    forall a. RawFilePath -> (CStringLen -> IO a) -> IO a
    B.useAsCStringLen RawFilePath
    ba ((CStringLen -> IO String) -> IO String)
    -> (CStringLen -> IO String) -> IO String
    forall a b. (a -> b) -> a -> b
    $ \CStringLen
    fp -> CStringLen -> IO String
    peekFilePathPosix CStringLen
    fp
     where
      peekFilePathPosix :: CStringLen -> IO String
      peekFilePathPosix :: CStringLen -> IO String
    peekFilePathPosix CStringLen
    fp = IO TextEncoding
    getFileSystemEncoding IO TextEncoding -> (TextEncoding -> IO String) -> IO String
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \TextEncoding
    enc -> TextEncoding -> CStringLen -> IO String
    GHC.peekCStringLen TextEncoding
    enc CStringLen
    fp

    -- | Wrapper around 'useAsCString', checking the encoded 'FilePath' for internal NUL octets as these are
    -- disallowed in POSIX filepaths. See https://gitlab.haskell.org/ghc/ghc/-/issues/13660
    useAsCStringSafe :: RawFilePath -> (CString -> IO a) -> IO a
    useAsCStringSafe :: forall a. RawFilePath -> (CString -> IO a) -> IO a
    useAsCStringSafe RawFilePath
    path CString -> IO a
    f = RawFilePath -> (CString -> IO a) -> IO a
    forall a. RawFilePath -> (CString -> IO a) -> IO a
    useAsCString RawFilePath
    path ((CString -> IO a) -> IO a) -> (CString -> IO a) -> IO a
    forall a b. (a -> b) -> a -> b
    $ \CString
    ptr -> do
        let len :: Int
    len = RawFilePath -> Int
    B.length RawFilePath
    path
        clen <- CString -> IO CSize
    c_strlen CString
    ptr
        if clen == fromIntegral len
            then f ptr
            else do
              path' <- either (const (BC.unpack path)) id <$> try @IOException (decodeWithBasePosix path)
              ioError (err path')
      where
        err :: String -> IOException
    err String
    path' =
            IOError
              { ioe_handle :: Maybe Handle
    ioe_handle = Maybe Handle
    forall a. Maybe a
    Nothing
              , ioe_type :: IOErrorType
    ioe_type = IOErrorType
    InvalidArgument
              , ioe_location :: String
    ioe_location = String
    "checkForInteriorNuls"
              , ioe_description :: String
    ioe_description = String
    "POSIX filepaths must not contain internal NUL octets."
              , ioe_errno :: Maybe CInt
    ioe_errno = Maybe CInt
    forall a. Maybe a
    Nothing
              , ioe_filename :: Maybe String
    ioe_filename = String -> Maybe String
    forall a. a -> Maybe a
    Just String
    path'
              }