-- |
-- Module      : Streamly.Internal.FileSystem.Posix.Errno
-- Copyright   : (c) 2024 Composewell Technologies
--
-- License     : BSD3
-- Maintainer  : streamly@composewell.com
-- Portability : GHC

module Streamly.Internal.FileSystem.Posix.Errno
    (
#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)
      throwErrnoPath
    , throwErrnoPathIfRetry
    , throwErrnoPathIfNullRetry
    , throwErrnoPathIfMinus1Retry
#endif
    )
where

#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)
import Foreign (Ptr, nullPtr)
import Foreign.C (getErrno, eINTR)
import Foreign.C.Error (errnoToIOError)
import Streamly.Internal.FileSystem.PosixPath (PosixPath(..))

import qualified Streamly.Internal.FileSystem.PosixPath as Path

-------------------------------------------------------------------------------
-- From unix
-------------------------------------------------------------------------------

-- | Same as 'throwErrno', but exceptions include the given path when
-- appropriate.
--
throwErrnoPath :: String -> PosixPath -> IO a
throwErrnoPath :: forall a. String -> PosixPath -> IO a
throwErrnoPath String
loc PosixPath
path =
  do
    Errno
errno <- IO Errno
getErrno
    -- XXX toString uses strict decoding, may fail
    IOError -> IO a
forall a. IOError -> IO a
ioError (String -> Errno -> Maybe Handle -> Maybe String -> IOError
errnoToIOError String
loc Errno
errno Maybe Handle
forall a. Maybe a
Nothing (String -> Maybe String
forall a. a -> Maybe a
Just (PosixPath -> String
forall a. IsPath PosixPath a => a -> String
Path.toString PosixPath
path)))

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

throwErrnoPathIfNullRetry :: String -> PosixPath -> IO (Ptr a) -> IO (Ptr a)
throwErrnoPathIfNullRetry :: forall a. String -> PosixPath -> IO (Ptr a) -> IO (Ptr a)
throwErrnoPathIfNullRetry = (Ptr a -> Bool) -> String -> PosixPath -> IO (Ptr a) -> IO (Ptr a)
forall a. (a -> Bool) -> String -> PosixPath -> IO a -> IO a
throwErrnoPathIfRetry (Ptr a -> Ptr a -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr a
forall a. Ptr a
nullPtr)

throwErrnoPathIfMinus1Retry :: (Eq a, Num a) =>
    String -> PosixPath -> IO a -> IO a
throwErrnoPathIfMinus1Retry :: forall a. (Eq a, Num a) => String -> PosixPath -> IO a -> IO a
throwErrnoPathIfMinus1Retry = (a -> Bool) -> String -> PosixPath -> IO a -> IO a
forall a. (a -> Bool) -> String -> PosixPath -> IO a -> IO a
throwErrnoPathIfRetry (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== -a
1)
#endif