{-# OPTIONS_GHC -cpp #-} {-# LANGUAGE CPP #-} module Workaround ( renameFile, setExecutable, getCurrentDirectory, installHandler, raiseSignal, Handler(..), Signal, sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE ) where #ifdef WIN32 import qualified System.Directory ( renameFile, getCurrentDirectory, removeFile ) import qualified Control.Exception ( block ) import qualified System.IO.Error ( isDoesNotExistError, ioError, catch ) #else import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal, sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE) import System.Directory ( renameFile, getCurrentDirectory ) import System.Posix.Files (fileMode,getFileStatus, setFileMode, setFileCreationMask, ownerReadMode, ownerWriteMode, ownerExecuteMode, groupReadMode, groupWriteMode, groupExecuteMode, otherReadMode, otherWriteMode, otherExecuteMode) import Data.Bits ( (.&.), (.|.), complement ) #endif #ifdef WIN32 -- Dummy implementation of POSIX signals data Handler = Default | Ignore | Catch (IO ()) type Signal = Int installHandler :: Signal -> Handler -> Maybe () -> IO () installHandler _ _ _ = return () raiseSignal :: Signal -> IO () raiseSignal _ = return () sigINT, {- sigKILL, -} sigHUP, {- sigQUIT, -} sigABRT, sigALRM, sigTERM, sigPIPE :: Signal sigINT = 0 -- not used: sigKILL = 0 sigHUP = 0 -- not used: sigQUIT = 0 sigABRT = 0 sigTERM = 0 sigPIPE = 0 sigALRM = 0 {- System.Directory.renameFile incorrectly fails when the new file already exists. This code works around that bug at the cost of losing atomic writes. -} renameFile :: FilePath -> FilePath -> IO () renameFile old new = Control.Exception.block $ System.Directory.renameFile old new `System.IO.Error.catch` \_ -> do System.Directory.removeFile new `System.IO.Error.catch` (\e -> if System.IO.Error.isDoesNotExistError e then return () else System.IO.Error.ioError e) System.Directory.renameFile old new setExecutable :: FilePath -> Bool -> IO () setExecutable _ _ = return () {- System.Directory.getCurrentDirectory returns a path with backslashes in it under windows, and some of the code gets confused by that, so we override getCurrentDirectory and translates '\\' to '/' -} getCurrentDirectory :: IO FilePath getCurrentDirectory = do d <- System.Directory.getCurrentDirectory return $ map rb d where rb '\\' = '/' rb c = c #else setExecutable :: FilePath -> Bool -> IO () setExecutable f ex = do st <- getFileStatus f umask <- setFileCreationMask 0 setFileCreationMask umask let rw = fileMode st .&. (ownerReadMode .|. ownerWriteMode .|. groupReadMode .|. groupWriteMode .|. otherReadMode .|. otherWriteMode) total = if ex then rw .|. ((ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode) .&. complement umask) else rw setFileMode f total #endif