{-# LANGUAGE CPP #-}
{-# OPTIONS_HADDOCK hide #-}
module Distribution.Compat.Internal.TempFile
( openTempFile
, openBinaryTempFile
, openNewBinaryFile
, createTempDirectory
) where
import Distribution.Compat.Exception
import System.FilePath ((</>))
import System.IO (Handle, openBinaryTempFile, openTempFile)
#if defined(__IO_MANAGER_WINIO__)
import System.IO (openBinaryTempFileWithDefaultPermissions)
#else
import Control.Exception (onException)
import Data.Bits ((.|.))
import Foreign.C (CInt, eEXIST, getErrno, errnoToIOError)
import GHC.IO.Handle.FD (fdToHandle)
import System.Posix.Internals (c_open, c_close, o_EXCL, o_BINARY, withFilePath,
o_CREAT, o_RDWR, o_NONBLOCK, o_NOCTTY)
#endif
import System.IO.Error (isAlreadyExistsError)
import System.Posix.Internals (c_getpid)
#if defined(mingw32_HOST_OS) || defined(ghcjs_HOST_OS)
import System.Directory ( createDirectory )
#else
import qualified System.Posix
#endif
openNewBinaryFile :: FilePath -> String -> IO (FilePath, Handle)
openNewBinaryFile :: FilePath -> FilePath -> IO (FilePath, Handle)
openNewBinaryFile FilePath
dir FilePath
template = do
#if defined(__IO_MANAGER_WINIO__)
FilePath -> FilePath -> IO (FilePath, Handle)
openBinaryTempFileWithDefaultPermissions FilePath
dir FilePath
template
#else
pid <- c_getpid
findTempName pid
where
(prefix,suffix) =
case break (== '.') $ reverse template of
(rev_suffix, "") -> (reverse rev_suffix, "")
(rev_suffix, '.':rest) -> (reverse rest, '.':reverse rev_suffix)
_ -> error "bug in System.IO.openTempFile"
oflags = rw_flags .|. o_EXCL .|. o_BINARY
findTempName x = do
fd <- withFilePath filepath $ \ f ->
c_open f oflags 0o666
if fd < 0
then do
errno <- getErrno
if errno == eEXIST
then findTempName (x+1)
else ioError (errnoToIOError "openNewBinaryFile" errno Nothing (Just dir))
else do
h <- fdToHandle fd `onException` c_close fd
return (filepath, h)
where
filename = prefix ++ show x ++ suffix
filepath = dir `combine` filename
combine a b
| null b = a
| null a = b
| last a == pathSeparator = a ++ b
| otherwise = a ++ [pathSeparator] ++ b
std_flags, output_flags, rw_flags :: CInt
std_flags = o_NONBLOCK .|. o_NOCTTY
output_flags = std_flags .|. o_CREAT
rw_flags = output_flags .|. o_RDWR
pathSeparator :: Char
#ifdef mingw32_HOST_OS
pathSeparator = '\\'
#else
pathSeparator = '/'
#endif
#endif
createTempDirectory :: FilePath -> String -> IO FilePath
createTempDirectory :: FilePath -> FilePath -> IO FilePath
createTempDirectory FilePath
dir FilePath
template = do
CPid
pid <- IO CPid
c_getpid
CPid -> IO FilePath
forall {t}. (Num t, Show t) => t -> IO FilePath
findTempName CPid
pid
where
findTempName :: t -> IO FilePath
findTempName t
x = do
let relpath :: FilePath
relpath = FilePath
template FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"-" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ t -> FilePath
forall a. Show a => a -> FilePath
show t
x
dirpath :: FilePath
dirpath = FilePath
dir FilePath -> FilePath -> FilePath
</> FilePath
relpath
Either IOException ()
r <- IO () -> IO (Either IOException ())
forall a. IO a -> IO (Either IOException a)
tryIO (IO () -> IO (Either IOException ()))
-> IO () -> IO (Either IOException ())
forall a b. (a -> b) -> a -> b
$ FilePath -> IO ()
mkPrivateDir FilePath
dirpath
case Either IOException ()
r of
Right ()
_ -> FilePath -> IO FilePath
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
relpath
Left IOException
e
| IOException -> Bool
isAlreadyExistsError IOException
e -> t -> IO FilePath
findTempName (t
x t -> t -> t
forall a. Num a => a -> a -> a
+ t
1)
| Bool
otherwise -> IOException -> IO FilePath
forall a. IOException -> IO a
ioError IOException
e
mkPrivateDir :: String -> IO ()
#if defined(mingw32_HOST_OS) || defined(ghcjs_HOST_OS)
mkPrivateDir :: FilePath -> IO ()
mkPrivateDir FilePath
s = FilePath -> IO ()
createDirectory FilePath
s
#else
mkPrivateDir s = System.Posix.createDirectory s 0o700
#endif