From 2e78aebe3bb0a05a27e6d8464cca244e6c44187e Mon Sep 17 00:00:00 2001 From: Duncan Coutts <duncan@haskell.org> Date: Wed, 23 Jan 2008 23:58:47 +0000 Subject: [PATCH] Rework withTempFile code and use System.IO.openTempFile where available The System.IO.openTempFile is much better because it opens the temp files securely. Howver it is only available in base-2 and only of GHC. In base-3 it is available for all implementations. So in practice that means it's only for GHC and we have to use our compatability implementation for hugs and nhc98. Not sure of the status for jhc. --- Distribution/Compat/TempFile.hs | 56 +++++++++++---------------------- Distribution/Simple/GHC.hs | 11 ++++--- Distribution/Simple/Program.hs | 9 +++--- Distribution/Simple/Utils.hs | 17 ++++++---- 4 files changed, 40 insertions(+), 53 deletions(-) diff --git a/Distribution/Compat/TempFile.hs b/Distribution/Compat/TempFile.hs index fc123e7211..5c5bb0c7f6 100644 --- a/Distribution/Compat/TempFile.hs +++ b/Distribution/Compat/TempFile.hs @@ -3,62 +3,42 @@ {-# OPTIONS_NHC98 -cpp #-} {-# OPTIONS_JHC -fcpp #-} -- #hide -module Distribution.Compat.TempFile (openTempFile, withTempFile) where +module Distribution.Compat.TempFile (openTempFile) where -import System.IO (openFile, Handle, IOMode(ReadWriteMode)) -import System.Directory (doesFileExist, removeFile) -import Control.Exception (finally,try) - -import System.FilePath ( (</>), (<.>) ) - -#if (__GLASGOW_HASKELL__ || __HUGS__) +#if __NHC__ || __HUGS__ +import System.IO (openFile, Handle, IOMode(ReadWriteMode)) +import System.Directory (doesFileExist) +import System.FilePath ((</>)) import System.Posix.Internals (c_getpid) #else -import System.Posix.Types (CPid(..)) +import System.IO (openTempFile) #endif - -- ------------------------------------------------------------ -- * temporary files -- ------------------------------------------------------------ --- TODO: this function *really really really* should be --- eliminated and replaced with System.IO.openTempFile, --- except that is currently GHC-only for no valid reason. +-- This is here for Haskell implementations that do not come with +-- System.IO.openTempFile. This includes nhc-1.20, hugs-2006.9. +-- TODO: Not sure about jhc +#if __NHC__ || __HUGS__ -- use a temporary filename that doesn't already exist. -- NB. *not* secure (we don't atomically lock the tmp file we get) openTempFile :: FilePath -> String -> IO (FilePath, Handle) openTempFile tmp_dir template - = do x <- getProcessID - findTempName x - where - findTempName x - = do let filename = template ++ show x - path = tmp_dir </> filename - b <- doesFileExist path - if b then findTempName (x+1) - else do hnd <- openFile path ReadWriteMode - return (path, hnd) - -#if !(__GLASGOW_HASKELL__ || __HUGS__) -foreign import ccall unsafe "getpid" c_getpid :: IO CPid -#endif - -getProcessID :: IO Int -getProcessID = c_getpid >>= return . fromIntegral - --- use a temporary filename that doesn't already exist. --- NB. *not* secure (we don't atomically lock the tmp file we get) -withTempFile :: FilePath -> String -> (FilePath -> IO a) -> IO a -withTempFile tmp_dir extn action = do x <- getProcessID findTempName x where + (templateBase, templateExt) = splitExtension template + findTempName :: Int -> IO (FilePath, Handle) findTempName x - = do let filename = ("tmp" ++ show x) <.> extn - path = tmp_dir </> filename + = do let path = tmp_dir </> (templateBase ++ show x) <.> templateExt b <- doesFileExist path if b then findTempName (x+1) - else action path `finally` try (removeFile path) + else do hnd <- openFile path ReadWriteMode + return (path, hnd) + getProcessID :: IO Int + getProcessID = fmap fromIntegral c_getpid +#endif diff --git a/Distribution/Simple/GHC.hs b/Distribution/Simple/GHC.hs index 2657a2b812..8c6c21584b 100644 --- a/Distribution/Simple/GHC.hs +++ b/Distribution/Simple/GHC.hs @@ -84,7 +84,6 @@ import Data.List ( nub, isPrefixOf ) import System.Directory ( removeFile, renameFile, getDirectoryContents, doesFileExist, getTemporaryDirectory ) -import Distribution.Compat.TempFile ( withTempFile ) import System.FilePath ( (</>), (<.>), takeExtension, takeDirectory, replaceExtension, splitExtension ) import System.IO (openFile, IOMode(WriteMode), hClose, hPutStrLn) @@ -131,13 +130,15 @@ configure verbosity hcPath hcPkgPath conf = do -- we need to find out if ld supports the -x flag (ldProg, conf''') <- requireProgram verbosity ldProgram' AnyVersion conf'' tempDir <- getTemporaryDirectory - ldx <- withTempFile tempDir "c" $ \testcfile -> - withTempFile tempDir "o" $ \testofile -> do - writeFile testcfile "int foo() {}\n" + ldx <- withTempFile tempDir ".c" $ \testcfile testchnd -> + withTempFile tempDir ".o" $ \testofile testohnd -> do + hPutStrLn testchnd "int foo() {}" + hClose testchnd; hClose testohnd rawSystemProgram verbosity ghcProg ["-c", testcfile, "-o", testofile] - withTempFile tempDir "o" $ \testofile' -> + withTempFile tempDir ".o" $ \testofile' testohnd' -> handle (\_ -> return False) $ do + hClose testohnd' rawSystemProgramStdout verbosity ldProg ["-x", "-r", testofile, "-o", testofile'] return True diff --git a/Distribution/Simple/Program.hs b/Distribution/Simple/Program.hs index 18d2addaba..ac7c77b6f8 100644 --- a/Distribution/Simple/Program.hs +++ b/Distribution/Simple/Program.hs @@ -84,14 +84,15 @@ module Distribution.Simple.Program ( ) where import qualified Data.Map as Map -import Distribution.Compat.TempFile (withTempFile) import Distribution.Simple.Utils (die, debug, warn, rawSystemExit, - rawSystemStdout, rawSystemStdout') + rawSystemStdout, rawSystemStdout', + withTempFile) import Distribution.Version (Version(..), readVersion, showVersion, VersionRange(..), withinRange, showVersionRange) import Distribution.Verbosity import System.Directory (doesFileExist, removeFile, findExecutable) import System.FilePath (dropExtension) +import System.IO (hClose) import System.IO.Error (try) import Control.Monad (join, foldM) import Control.Exception as Exception (catch) @@ -570,8 +571,8 @@ hsc2hsProgram = (simpleProgram "hsc2hs") { case maybeVersion of Nothing -> return Nothing Just version -> - withTempFile "dist" "hsc" $ \hsc -> do - writeFile hsc "" + withTempFile "dist" ".hsc" $ \hsc hnd -> do + hClose hnd (str, _) <- rawSystemStdout' verbosity path [hsc, "--cflag=--version"] try $ removeFile (dropExtension hsc ++ "_hsc_make.c") case words str of diff --git a/Distribution/Simple/Utils.hs b/Distribution/Simple/Utils.hs index 7b47055311..7fb5a2d700 100644 --- a/Distribution/Simple/Utils.hs +++ b/Distribution/Simple/Utils.hs @@ -70,6 +70,7 @@ module Distribution.Simple.Utils ( currentDir, dotToSep, findFile, + withTempFile, defaultPackageDesc, findPackageDesc, defaultHookedPackageDesc, @@ -121,13 +122,9 @@ import System.Cmd (system) import Control.Exception (evaluate) import System.Process (runProcess, waitForProcess) #endif -import System.IO (hClose) +import System.IO (Handle, hClose) -#if __GLASGOW_HASKELL__ >= 604 import Distribution.Compat.TempFile (openTempFile) -#else -import Distribution.Compat.TempFile (withTempFile) -#endif import Distribution.Verbosity #ifdef DEBUG @@ -445,7 +442,15 @@ copyDirectoryRecursiveVerbose verbosity srcDir destDir = do fmap (filter (not . flip elem [".", ".."])) . getDirectoryContents - +-- | Use a temporary filename that doesn't already exist. +-- +withTempFile :: FilePath -- ^ Temp dir to create the file in + -> String -- ^ File name template. See 'openTempFile'. + -> (FilePath -> Handle -> IO a) -> IO a +withTempFile tmpDir template action = + bracket (openTempFile tmpDir template) + (\(name, handle) -> hClose handle >> removeFile name) + (uncurry action) -- | The path name that represents the current directory. -- In Unix, it's @\".\"@, but this is system-specific. -- GitLab