-- | Provides the 'MonadPosixCompat' typeclass.
--
-- @since 0.1
module Effects.System.PosixCompat
  ( -- * Effect
    MonadPosixCompat (..),

    -- * PathType
    PathType (..),

    -- ** Functions
    displayPathType,
    throwIfWrongPathType,
    isPathType,
    getPathType,
  )
where

import Control.Monad (unless)
import Control.Monad.Catch (MonadCatch)
import Control.Monad.Trans.Class (MonadTrans (lift))
import Control.Monad.Trans.Reader (ReaderT)
import Data.Functor ((<&>))
import FileSystem.IO qualified as FS.IO
import FileSystem.PathType
  ( PathType
      ( PathTypeDirectory,
        PathTypeFile,
        PathTypeOther,
        PathTypeSymbolicLink
      ),
    displayPathType,
  )
import GHC.IO.Exception (IOErrorType (InappropriateType))
import GHC.Stack (HasCallStack)
import System.PosixCompat.Files (FileStatus, PathVar)
import System.PosixCompat.Files qualified as PFiles
import System.PosixCompat.Types
  ( DeviceID,
    EpochTime,
    Fd,
    FileMode,
    FileOffset,
    GroupID,
    Limit,
    UserID,
  )

{- HLINT ignore "Redundant bracket" -}

-- | Class for unix-compat effects.
--
-- @since 0.1
class (Monad m) => MonadPosixCompat m where
  -- System.PosixCompat.Files

  -- | @since 0.1
  setFileMode :: (HasCallStack) => FilePath -> FileMode -> m ()

  -- | @since 0.1
  setFdMode :: (HasCallStack) => Fd -> FileMode -> m ()

  -- | @since 0.1
  setFileCreationMask :: (HasCallStack) => FileMode -> m FileMode

  -- | @since 0.1
  fileAccess :: (HasCallStack) => FilePath -> Bool -> Bool -> Bool -> m Bool

  -- | @since 0.1
  fileExist :: (HasCallStack) => FilePath -> m Bool

  -- | @since 0.1
  getFileStatus :: (HasCallStack) => FilePath -> m FileStatus

  -- | @since 0.1
  getFdStatus :: (HasCallStack) => Fd -> m FileStatus

  -- | @since 0.1
  getSymbolicLinkStatus :: (HasCallStack) => FilePath -> m FileStatus

  -- | @since 0.1
  createNamedPipe :: (HasCallStack) => FilePath -> FileMode -> m ()

  -- | @since 0.1
  createDevice :: (HasCallStack) => FilePath -> FileMode -> DeviceID -> m ()

  -- | @since 0.1
  createLink :: (HasCallStack) => FilePath -> FilePath -> m ()

  -- | @since 0.1
  removeLink :: (HasCallStack) => FilePath -> m ()

  -- | @since 0.1
  createSymbolicLink :: (HasCallStack) => FilePath -> FilePath -> m ()

  -- | @since 0.1
  readSymbolicLink :: (HasCallStack) => FilePath -> m FilePath

  -- | @since 0.1
  rename :: (HasCallStack) => FilePath -> FilePath -> m ()

  -- | @since 0.1
  setOwnerAndGroup :: (HasCallStack) => FilePath -> UserID -> GroupID -> m ()

  -- | @since 0.1
  setFdOwnerAndGroup :: (HasCallStack) => Fd -> UserID -> GroupID -> m ()

  -- | @since 0.1
  setSymbolicLinkOwnerAndGroup :: (HasCallStack) => FilePath -> UserID -> GroupID -> m ()

  -- | @since 0.1
  setFileTimes :: (HasCallStack) => FilePath -> EpochTime -> EpochTime -> m ()

  -- | @since 0.1
  touchFile :: (HasCallStack) => FilePath -> m ()

  -- | @since 0.1
  setFileSize :: (HasCallStack) => FilePath -> FileOffset -> m ()

  -- | @since 0.1
  setFdSize :: (HasCallStack) => Fd -> FileOffset -> m ()

  -- | @since 0.1
  getPathVar :: (HasCallStack) => FilePath -> PathVar -> m Limit

  -- | @since 0.1
  getFdPathVar :: (HasCallStack) => Fd -> PathVar -> m Limit

-- | @since 0.1
instance MonadPosixCompat IO where
  setFileMode :: HasCallStack => FilePath -> FileMode -> IO ()
setFileMode = FilePath -> FileMode -> IO ()
PFiles.setFileMode
  {-# INLINEABLE setFileMode #-}
  setFdMode :: HasCallStack => Fd -> FileMode -> IO ()
setFdMode = Fd -> FileMode -> IO ()
PFiles.setFdMode
  {-# INLINEABLE setFdMode #-}
  setFileCreationMask :: HasCallStack => FileMode -> IO FileMode
setFileCreationMask = FileMode -> IO FileMode
PFiles.setFileCreationMask
  {-# INLINEABLE setFileCreationMask #-}
  fileAccess :: HasCallStack => FilePath -> Bool -> Bool -> Bool -> IO Bool
fileAccess = FilePath -> Bool -> Bool -> Bool -> IO Bool
PFiles.fileAccess
  {-# INLINEABLE fileAccess #-}
  fileExist :: HasCallStack => FilePath -> IO Bool
fileExist = FilePath -> IO Bool
PFiles.fileExist
  {-# INLINEABLE fileExist #-}
  getFileStatus :: HasCallStack => FilePath -> IO FileStatus
getFileStatus = FilePath -> IO FileStatus
PFiles.getFileStatus
  {-# INLINEABLE getFileStatus #-}
  getFdStatus :: HasCallStack => Fd -> IO FileStatus
getFdStatus = Fd -> IO FileStatus
PFiles.getFdStatus
  {-# INLINEABLE getFdStatus #-}
  getSymbolicLinkStatus :: HasCallStack => FilePath -> IO FileStatus
getSymbolicLinkStatus = FilePath -> IO FileStatus
PFiles.getSymbolicLinkStatus
  {-# INLINEABLE getSymbolicLinkStatus #-}
  createNamedPipe :: HasCallStack => FilePath -> FileMode -> IO ()
createNamedPipe = FilePath -> FileMode -> IO ()
PFiles.createNamedPipe
  {-# INLINEABLE createNamedPipe #-}
  createDevice :: HasCallStack => FilePath -> FileMode -> DeviceID -> IO ()
createDevice = FilePath -> FileMode -> DeviceID -> IO ()
PFiles.createDevice
  {-# INLINEABLE createDevice #-}
  createLink :: HasCallStack => FilePath -> FilePath -> IO ()
createLink = FilePath -> FilePath -> IO ()
PFiles.createLink
  {-# INLINEABLE createLink #-}
  removeLink :: HasCallStack => FilePath -> IO ()
removeLink = FilePath -> IO ()
PFiles.removeLink
  {-# INLINEABLE removeLink #-}
  createSymbolicLink :: HasCallStack => FilePath -> FilePath -> IO ()
createSymbolicLink = FilePath -> FilePath -> IO ()
PFiles.createSymbolicLink
  {-# INLINEABLE createSymbolicLink #-}
  readSymbolicLink :: HasCallStack => FilePath -> IO FilePath
readSymbolicLink = FilePath -> IO FilePath
PFiles.readSymbolicLink
  {-# INLINEABLE readSymbolicLink #-}
  rename :: HasCallStack => FilePath -> FilePath -> IO ()
rename = FilePath -> FilePath -> IO ()
PFiles.rename
  {-# INLINEABLE rename #-}
  setOwnerAndGroup :: HasCallStack => FilePath -> UserID -> GroupID -> IO ()
setOwnerAndGroup = FilePath -> UserID -> GroupID -> IO ()
PFiles.setOwnerAndGroup
  {-# INLINEABLE setOwnerAndGroup #-}
  setFdOwnerAndGroup :: HasCallStack => Fd -> UserID -> GroupID -> IO ()
setFdOwnerAndGroup = Fd -> UserID -> GroupID -> IO ()
PFiles.setFdOwnerAndGroup
  {-# INLINEABLE setFdOwnerAndGroup #-}
  setSymbolicLinkOwnerAndGroup :: HasCallStack => FilePath -> UserID -> GroupID -> IO ()
setSymbolicLinkOwnerAndGroup = FilePath -> UserID -> GroupID -> IO ()
PFiles.setSymbolicLinkOwnerAndGroup
  {-# INLINEABLE setSymbolicLinkOwnerAndGroup #-}
  setFileTimes :: HasCallStack => FilePath -> EpochTime -> EpochTime -> IO ()
setFileTimes = FilePath -> EpochTime -> EpochTime -> IO ()
PFiles.setFileTimes
  {-# INLINEABLE setFileTimes #-}
  touchFile :: HasCallStack => FilePath -> IO ()
touchFile = FilePath -> IO ()
PFiles.touchFile
  {-# INLINEABLE touchFile #-}
  setFileSize :: HasCallStack => FilePath -> FileOffset -> IO ()
setFileSize = FilePath -> FileOffset -> IO ()
PFiles.setFileSize
  {-# INLINEABLE setFileSize #-}
  setFdSize :: HasCallStack => Fd -> FileOffset -> IO ()
setFdSize = Fd -> FileOffset -> IO ()
PFiles.setFdSize
  {-# INLINEABLE setFdSize #-}
  getPathVar :: HasCallStack => FilePath -> PathVar -> IO Limit
getPathVar = FilePath -> PathVar -> IO Limit
PFiles.getPathVar
  {-# INLINEABLE getPathVar #-}
  getFdPathVar :: HasCallStack => Fd -> PathVar -> IO Limit
getFdPathVar = Fd -> PathVar -> IO Limit
PFiles.getFdPathVar
  {-# INLINEABLE getFdPathVar #-}

-- | @since 0.1
instance (MonadPosixCompat m) => MonadPosixCompat (ReaderT e m) where
  setFileMode :: HasCallStack => FilePath -> FileMode -> ReaderT e m ()
setFileMode FilePath
p = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FileMode -> m ()) -> FileMode -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FileMode -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> FileMode -> m ()
setFileMode FilePath
p
  {-# INLINEABLE setFileMode #-}
  setFdMode :: HasCallStack => Fd -> FileMode -> ReaderT e m ()
setFdMode Fd
fd = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FileMode -> m ()) -> FileMode -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fd -> FileMode -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
Fd -> FileMode -> m ()
setFdMode Fd
fd
  {-# INLINEABLE setFdMode #-}
  setFileCreationMask :: HasCallStack => FileMode -> ReaderT e m FileMode
setFileCreationMask = m FileMode -> ReaderT e m FileMode
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m FileMode -> ReaderT e m FileMode)
-> (FileMode -> m FileMode) -> FileMode -> ReaderT e m FileMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileMode -> m FileMode
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FileMode -> m FileMode
setFileCreationMask
  {-# INLINEABLE setFileCreationMask #-}
  fileAccess :: HasCallStack =>
FilePath -> Bool -> Bool -> Bool -> ReaderT e m Bool
fileAccess FilePath
p Bool
a Bool
b = m Bool -> ReaderT e m Bool
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m Bool -> ReaderT e m Bool)
-> (Bool -> m Bool) -> Bool -> ReaderT e m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Bool -> Bool -> Bool -> m Bool
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> Bool -> Bool -> Bool -> m Bool
fileAccess FilePath
p Bool
a Bool
b
  {-# INLINEABLE fileAccess #-}
  fileExist :: HasCallStack => FilePath -> ReaderT e m Bool
fileExist = m Bool -> ReaderT e m Bool
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m Bool -> ReaderT e m Bool)
-> (FilePath -> m Bool) -> FilePath -> ReaderT e m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m Bool
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> m Bool
fileExist
  {-# INLINEABLE fileExist #-}
  getFileStatus :: HasCallStack => FilePath -> ReaderT e m FileStatus
getFileStatus = m FileStatus -> ReaderT e m FileStatus
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m FileStatus -> ReaderT e m FileStatus)
-> (FilePath -> m FileStatus) -> FilePath -> ReaderT e m FileStatus
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m FileStatus
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> m FileStatus
getFileStatus
  {-# INLINEABLE getFileStatus #-}
  getFdStatus :: HasCallStack => Fd -> ReaderT e m FileStatus
getFdStatus = m FileStatus -> ReaderT e m FileStatus
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m FileStatus -> ReaderT e m FileStatus)
-> (Fd -> m FileStatus) -> Fd -> ReaderT e m FileStatus
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fd -> m FileStatus
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
Fd -> m FileStatus
getFdStatus
  {-# INLINEABLE getFdStatus #-}
  getSymbolicLinkStatus :: HasCallStack => FilePath -> ReaderT e m FileStatus
getSymbolicLinkStatus = m FileStatus -> ReaderT e m FileStatus
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m FileStatus -> ReaderT e m FileStatus)
-> (FilePath -> m FileStatus) -> FilePath -> ReaderT e m FileStatus
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m FileStatus
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> m FileStatus
getSymbolicLinkStatus
  {-# INLINEABLE getSymbolicLinkStatus #-}
  createNamedPipe :: HasCallStack => FilePath -> FileMode -> ReaderT e m ()
createNamedPipe FilePath
p = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FileMode -> m ()) -> FileMode -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FileMode -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> FileMode -> m ()
createNamedPipe FilePath
p
  {-# INLINEABLE createNamedPipe #-}
  createDevice :: HasCallStack => FilePath -> FileMode -> DeviceID -> ReaderT e m ()
createDevice FilePath
p FileMode
m = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (DeviceID -> m ()) -> DeviceID -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FileMode -> DeviceID -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> FileMode -> DeviceID -> m ()
createDevice FilePath
p FileMode
m
  {-# INLINEABLE createDevice #-}
  createLink :: HasCallStack => FilePath -> FilePath -> ReaderT e m ()
createLink FilePath
p = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FilePath -> m ()) -> FilePath -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> FilePath -> m ()
createLink FilePath
p
  {-# INLINEABLE createLink #-}
  removeLink :: HasCallStack => FilePath -> ReaderT e m ()
removeLink = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FilePath -> m ()) -> FilePath -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> m ()
removeLink
  {-# INLINEABLE removeLink #-}
  createSymbolicLink :: HasCallStack => FilePath -> FilePath -> ReaderT e m ()
createSymbolicLink FilePath
p = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FilePath -> m ()) -> FilePath -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> FilePath -> m ()
createSymbolicLink FilePath
p
  {-# INLINEABLE createSymbolicLink #-}
  readSymbolicLink :: HasCallStack => FilePath -> ReaderT e m FilePath
readSymbolicLink = m FilePath -> ReaderT e m FilePath
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m FilePath -> ReaderT e m FilePath)
-> (FilePath -> m FilePath) -> FilePath -> ReaderT e m FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m FilePath
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> m FilePath
readSymbolicLink
  {-# INLINEABLE readSymbolicLink #-}
  rename :: HasCallStack => FilePath -> FilePath -> ReaderT e m ()
rename FilePath
p = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FilePath -> m ()) -> FilePath -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> FilePath -> m ()
rename FilePath
p
  {-# INLINEABLE rename #-}
  setOwnerAndGroup :: HasCallStack => FilePath -> UserID -> GroupID -> ReaderT e m ()
setOwnerAndGroup FilePath
p UserID
u = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (GroupID -> m ()) -> GroupID -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> UserID -> GroupID -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> UserID -> GroupID -> m ()
setOwnerAndGroup FilePath
p UserID
u
  {-# INLINEABLE setOwnerAndGroup #-}
  setFdOwnerAndGroup :: HasCallStack => Fd -> UserID -> GroupID -> ReaderT e m ()
setFdOwnerAndGroup Fd
fd UserID
u = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (GroupID -> m ()) -> GroupID -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fd -> UserID -> GroupID -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
Fd -> UserID -> GroupID -> m ()
setFdOwnerAndGroup Fd
fd UserID
u
  {-# INLINEABLE setFdOwnerAndGroup #-}
  setSymbolicLinkOwnerAndGroup :: HasCallStack => FilePath -> UserID -> GroupID -> ReaderT e m ()
setSymbolicLinkOwnerAndGroup FilePath
p UserID
u = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (GroupID -> m ()) -> GroupID -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> UserID -> GroupID -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> UserID -> GroupID -> m ()
setSymbolicLinkOwnerAndGroup FilePath
p UserID
u
  {-# INLINEABLE setSymbolicLinkOwnerAndGroup #-}
  setFileTimes :: HasCallStack =>
FilePath -> EpochTime -> EpochTime -> ReaderT e m ()
setFileTimes FilePath
p EpochTime
t = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (EpochTime -> m ()) -> EpochTime -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> EpochTime -> EpochTime -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> EpochTime -> EpochTime -> m ()
setFileTimes FilePath
p EpochTime
t
  {-# INLINEABLE setFileTimes #-}
  touchFile :: HasCallStack => FilePath -> ReaderT e m ()
touchFile = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FilePath -> m ()) -> FilePath -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> m ()
touchFile
  {-# INLINEABLE touchFile #-}
  setFileSize :: HasCallStack => FilePath -> FileOffset -> ReaderT e m ()
setFileSize FilePath
p = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FileOffset -> m ()) -> FileOffset -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FileOffset -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> FileOffset -> m ()
setFileSize FilePath
p
  {-# INLINEABLE setFileSize #-}
  setFdSize :: HasCallStack => Fd -> FileOffset -> ReaderT e m ()
setFdSize Fd
fd = m () -> ReaderT e m ()
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> ReaderT e m ())
-> (FileOffset -> m ()) -> FileOffset -> ReaderT e m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fd -> FileOffset -> m ()
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
Fd -> FileOffset -> m ()
setFdSize Fd
fd
  {-# INLINEABLE setFdSize #-}
  getPathVar :: HasCallStack => FilePath -> PathVar -> ReaderT e m Limit
getPathVar FilePath
p = m Limit -> ReaderT e m Limit
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m Limit -> ReaderT e m Limit)
-> (PathVar -> m Limit) -> PathVar -> ReaderT e m Limit
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> PathVar -> m Limit
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> PathVar -> m Limit
getPathVar FilePath
p
  {-# INLINEABLE getPathVar #-}
  getFdPathVar :: HasCallStack => Fd -> PathVar -> ReaderT e m Limit
getFdPathVar Fd
fd = m Limit -> ReaderT e m Limit
forall (m :: * -> *) a. Monad m => m a -> ReaderT e m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m Limit -> ReaderT e m Limit)
-> (PathVar -> m Limit) -> PathVar -> ReaderT e m Limit
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fd -> PathVar -> m Limit
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
Fd -> PathVar -> m Limit
getFdPathVar Fd
fd
  {-# INLINEABLE getFdPathVar #-}

-- | Throws 'IOException' if the path does not exist or the expected path type
-- does not match actual.
--
-- @since 0.1
throwIfWrongPathType ::
  ( HasCallStack,
    MonadCatch m,
    MonadPosixCompat m
  ) =>
  String ->
  PathType ->
  FilePath ->
  m ()
throwIfWrongPathType :: forall (m :: * -> *).
(HasCallStack, MonadCatch m, MonadPosixCompat m) =>
FilePath -> PathType -> FilePath -> m ()
throwIfWrongPathType FilePath
location PathType
expected FilePath
path = do
  PathType
actual <- FilePath -> m PathType
forall (m :: * -> *).
(HasCallStack, MonadPosixCompat m) =>
FilePath -> m PathType
getPathType FilePath
path

  let err :: FilePath
err =
        [FilePath] -> FilePath
forall a. Monoid a => [a] -> a
mconcat
          [ FilePath
"Expected path to have type ",
            PathType -> FilePath
forall a. IsString a => PathType -> a
displayPathType PathType
expected,
            FilePath
", but detected ",
            PathType -> FilePath
forall a. IsString a => PathType -> a
displayPathType PathType
actual
          ]

  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (PathType
expected PathType -> PathType -> Bool
forall a. Eq a => a -> a -> Bool
== PathType
actual) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
    FilePath -> FilePath -> IOErrorType -> FilePath -> m ()
forall (m :: * -> *) a.
(HasCallStack, MonadThrow m) =>
FilePath -> FilePath -> IOErrorType -> FilePath -> m a
FS.IO.throwPathIOErrorFilePath
      FilePath
path
      FilePath
location
      IOErrorType
InappropriateType
      FilePath
err
{-# INLINEABLE throwIfWrongPathType #-}

-- | Checks that the path type matches the expectation. Throws
-- 'IOException' if the path does not exist or the type cannot be detected.
--
-- @since 0.1
isPathType ::
  ( HasCallStack,
    MonadPosixCompat m
  ) =>
  PathType ->
  FilePath ->
  m Bool
isPathType :: forall (m :: * -> *).
(HasCallStack, MonadPosixCompat m) =>
PathType -> FilePath -> m Bool
isPathType PathType
expected = (PathType -> Bool) -> m PathType -> m Bool
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (PathType -> PathType -> Bool
forall a. Eq a => a -> a -> Bool
== PathType
expected) (m PathType -> m Bool)
-> (FilePath -> m PathType) -> FilePath -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> m PathType
forall (m :: * -> *).
(HasCallStack, MonadPosixCompat m) =>
FilePath -> m PathType
getPathType
{-# INLINEABLE isPathType #-}

-- | Returns the type for a given path without following symlinks.
-- Throws 'IOException' if the path does not exist or the type cannot be
-- detected.
--
-- @since 0.1
getPathType ::
  ( HasCallStack,
    MonadPosixCompat m
  ) =>
  FilePath ->
  m PathType
getPathType :: forall (m :: * -> *).
(HasCallStack, MonadPosixCompat m) =>
FilePath -> m PathType
getPathType FilePath
path =
  -- NOTE: We use getSymbolicLinkStatus instead of getFileStatus because
  -- the latter follows symlinks, which we do not want.
  FilePath -> m FileStatus
forall (m :: * -> *).
(MonadPosixCompat m, HasCallStack) =>
FilePath -> m FileStatus
getSymbolicLinkStatus FilePath
path m FileStatus -> (FileStatus -> PathType) -> m PathType
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \FileStatus
status ->
    if
      | FileStatus -> Bool
PFiles.isSymbolicLink FileStatus
status -> PathType
PathTypeSymbolicLink
      | FileStatus -> Bool
PFiles.isDirectory FileStatus
status -> PathType
PathTypeDirectory
      | FileStatus -> Bool
PFiles.isRegularFile FileStatus
status -> PathType
PathTypeFile
      | Bool
otherwise -> PathType
PathTypeOther
{-# INLINEABLE getPathType #-}