content: {-# LANGUAGE CPP #-}
  module IdeSession.Util.PortableFiles (
      setFileTimes
    , getFileStatus
    , modificationTime
    , toExecutable
    , moduleNameToExeName
  ) where
  
  
  import System.PosixCompat.Types
  import System.PosixCompat.Files hiding (setFileTimes)
  
  #ifdef VERSION_unix
  import qualified System.Posix.Files as Posix
  #else
  import Foreign
  import Data.Time.Clock.POSIX
  import System.FilePath.Posix
  import qualified System.Win32 as Win32
  import Control.Exception (bracket)
  #endif
  
  setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO ()
  
  -- Converts a module name to and executable file name
  moduleNameToExeName :: String -> String
  
  -- Converts a name of an a executable to the corresponding file name
  toExecutable :: String -> String
  
  #ifdef VERSION_unix
  
  setFileTimes = Posix.setFileTimes
  
  moduleNameToExeName = id
  
  toExecutable = id
  
  #else
  
  -- Unlike `utime`, which doesn't work for directories on Windows, this works for both for files and directories
  -- Mostly copied from @System.Directory@ 1.2.3.0
  setFileTimes path atime mtime =
    bracket (openFileHandle path' Win32.gENERIC_WRITE)
            Win32.closeHandle $ \ handle ->
      with (posixToWindowsTime atime) $ \ atime' ->
        with (posixToWindowsTime mtime) $ \ mtime' ->
          Win32.failIf_ not "setFileTimes" $
            Win32.c_SetFileTime handle nullPtr atime' mtime'
    where
      path'  = normalise path             -- handle empty paths
      windowsPosixEpochDifference :: Num a => a
      windowsPosixEpochDifference = 116444736000000000
      posixToWindowsTime :: EpochTime -> Win32.FILETIME
      posixToWindowsTime t = Win32.FILETIME $
        truncate ((realToFrac t :: POSIXTime) * 10000000 + windowsPosixEpochDifference)
      openFileHandle :: String -> Win32.AccessMode -> IO Win32.HANDLE
      openFileHandle p mode = Win32.createFile p mode share Nothing
                                               Win32.oPEN_EXISTING flags Nothing
        where share =  Win32.fILE_SHARE_DELETE
                   .|. Win32.fILE_SHARE_READ
                   .|. Win32.fILE_SHARE_WRITE
              flags =  Win32.fILE_ATTRIBUTE_NORMAL
                   .|. Win32.fILE_FLAG_BACKUP_SEMANTICS -- required for directories
  
  
  moduleNameToExeName = toExecutable
  
  toExecutable e = e ++ ".exe"
  #endif
  