-{-# OPTIONS_GHC -fno-implicit-prelude #-}
+{-# OPTIONS_GHC -XNoImplicitPrelude #-}
-----------------------------------------------------------------------------
-- |
-- Module : System.IO
module System.IO (
-- * The IO monad
- IO, -- instance MonadFix
- fixIO, -- :: (a -> IO a) -> IO a
+ IO, -- instance MonadFix
+ fixIO, -- :: (a -> IO a) -> IO a
-- * Files and handles
- FilePath, -- :: String
+ FilePath, -- :: String
- Handle, -- abstract, instance of: Eq, Show.
+ Handle, -- abstract, instance of: Eq, Show.
-- ** Standard handles
-- ** Opening files
withFile,
- openFile, -- :: FilePath -> IOMode -> IO Handle
+ openFile, -- :: FilePath -> IOMode -> IO Handle
IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),
-- ** Closing files
- hClose, -- :: Handle -> IO ()
+ hClose, -- :: Handle -> IO ()
-- ** Special cases
-- | These functions are also exported by the "Prelude".
- readFile, -- :: FilePath -> IO String
- writeFile, -- :: FilePath -> String -> IO ()
- appendFile, -- :: FilePath -> String -> IO ()
+ readFile, -- :: FilePath -> IO String
+ writeFile, -- :: FilePath -> String -> IO ()
+ appendFile, -- :: FilePath -> String -> IO ()
-- ** File locking
-- ** Determining and changing the size of a file
- hFileSize, -- :: Handle -> IO Integer
+ hFileSize, -- :: Handle -> IO Integer
#ifdef __GLASGOW_HASKELL__
hSetFileSize, -- :: Handle -> Integer -> IO ()
#endif
-- ** Detecting the end of input
- hIsEOF, -- :: Handle -> IO Bool
- isEOF, -- :: IO Bool
+ hIsEOF, -- :: Handle -> IO Bool
+ isEOF, -- :: IO Bool
-- ** Buffering operations
BufferMode(NoBuffering,LineBuffering,BlockBuffering),
- hSetBuffering, -- :: Handle -> BufferMode -> IO ()
- hGetBuffering, -- :: Handle -> IO BufferMode
- hFlush, -- :: Handle -> IO ()
+ hSetBuffering, -- :: Handle -> BufferMode -> IO ()
+ hGetBuffering, -- :: Handle -> IO BufferMode
+ hFlush, -- :: Handle -> IO ()
-- ** Repositioning handles
- hGetPosn, -- :: Handle -> IO HandlePosn
- hSetPosn, -- :: HandlePosn -> IO ()
+ hGetPosn, -- :: Handle -> IO HandlePosn
+ hSetPosn, -- :: HandlePosn -> IO ()
HandlePosn, -- abstract, instance of: Eq, Show.
- hSeek, -- :: Handle -> SeekMode -> Integer -> IO ()
+ hSeek, -- :: Handle -> SeekMode -> Integer -> IO ()
SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
#if !defined(__NHC__)
- hTell, -- :: Handle -> IO Integer
+ hTell, -- :: Handle -> IO Integer
#endif
-- ** Handle properties
-- ** Terminal operations (not portable: GHC\/Hugs only)
#if !defined(__NHC__)
- hIsTerminalDevice, -- :: Handle -> IO Bool
+ hIsTerminalDevice, -- :: Handle -> IO Bool
- hSetEcho, -- :: Handle -> Bool -> IO ()
- hGetEcho, -- :: Handle -> IO Bool
+ hSetEcho, -- :: Handle -> Bool -> IO ()
+ hGetEcho, -- :: Handle -> IO Bool
#endif
-- ** Showing handle state (not portable: GHC only)
#ifdef __GLASGOW_HASKELL__
- hShow, -- :: Handle -> IO String
+ hShow, -- :: Handle -> IO String
#endif
-- * Text input and output
-- ** Text input
- hWaitForInput, -- :: Handle -> Int -> IO Bool
- hReady, -- :: Handle -> IO Bool
- hGetChar, -- :: Handle -> IO Char
- hGetLine, -- :: Handle -> IO [Char]
- hLookAhead, -- :: Handle -> IO Char
- hGetContents, -- :: Handle -> IO [Char]
+ hWaitForInput, -- :: Handle -> Int -> IO Bool
+ hReady, -- :: Handle -> IO Bool
+ hGetChar, -- :: Handle -> IO Char
+ hGetLine, -- :: Handle -> IO [Char]
+ hLookAhead, -- :: Handle -> IO Char
+ hGetContents, -- :: Handle -> IO [Char]
-- ** Text output
- hPutChar, -- :: Handle -> Char -> IO ()
- hPutStr, -- :: Handle -> [Char] -> IO ()
- hPutStrLn, -- :: Handle -> [Char] -> IO ()
- hPrint, -- :: Show a => Handle -> a -> IO ()
+ hPutChar, -- :: Handle -> Char -> IO ()
+ hPutStr, -- :: Handle -> [Char] -> IO ()
+ hPutStrLn, -- :: Handle -> [Char] -> IO ()
+ hPrint, -- :: Show a => Handle -> a -> IO ()
-- ** Special cases for standard input and output
-- | These functions are also exported by the "Prelude".
- interact, -- :: (String -> String) -> IO ()
- putChar, -- :: Char -> IO ()
- putStr, -- :: String -> IO ()
- putStrLn, -- :: String -> IO ()
- print, -- :: Show a => a -> IO ()
- getChar, -- :: IO Char
- getLine, -- :: IO String
- getContents, -- :: IO String
- readIO, -- :: Read a => String -> IO a
- readLn, -- :: Read a => IO a
+ interact, -- :: (String -> String) -> IO ()
+ putChar, -- :: Char -> IO ()
+ putStr, -- :: String -> IO ()
+ putStrLn, -- :: String -> IO ()
+ print, -- :: Show a => a -> IO ()
+ getChar, -- :: IO Char
+ getLine, -- :: IO String
+ getContents, -- :: IO String
+ readIO, -- :: Read a => String -> IO a
+ readLn, -- :: Read a => IO a
-- * Binary input and output
withBinaryFile,
- openBinaryFile, -- :: FilePath -> IOMode -> IO Handle
- hSetBinaryMode, -- :: Handle -> Bool -> IO ()
- hPutBuf, -- :: Handle -> Ptr a -> Int -> IO ()
- hGetBuf, -- :: Handle -> Ptr a -> Int -> IO Int
+ openBinaryFile, -- :: FilePath -> IOMode -> IO Handle
+ hSetBinaryMode, -- :: Handle -> Bool -> IO ()
+ hPutBuf, -- :: Handle -> Ptr a -> Int -> IO ()
+ hGetBuf, -- :: Handle -> Ptr a -> Int -> IO Int
#if !defined(__NHC__) && !defined(__HUGS__)
- hPutBufNonBlocking, -- :: Handle -> Ptr a -> Int -> IO Int
- hGetBufNonBlocking, -- :: Handle -> Ptr a -> Int -> IO Int
+ hPutBufNonBlocking, -- :: Handle -> Ptr a -> Int -> IO Int
+ hGetBufNonBlocking, -- :: Handle -> Ptr a -> Int -> IO Int
#endif
- -- * Temporary files (not portable: GHC\/Hugs only)
+ -- * Temporary files
-#if !defined(__NHC__)
openTempFile,
openBinaryTempFile,
-#endif
) where
+import Control.Exception hiding (bracket)
+
#ifndef __NHC__
import Data.Bits
import Data.List
#endif
#ifdef __GLASGOW_HASKELL__
-import GHC.Exception as ExceptionBase hiding (catch)
+import GHC.IOBase as ExceptionBase
#endif
#ifdef __HUGS__
import Hugs.Exception as ExceptionBase
#ifdef __GLASGOW_HASKELL__
import GHC.Base
-import GHC.IOBase -- Together these four Prelude modules define
-import GHC.Handle -- all the stuff exported by IO for the GHC version
+import GHC.IOBase -- Together these four Prelude modules define
+import GHC.Handle -- all the stuff exported by IO for the GHC version
import GHC.IO
import GHC.Exception
import GHC.Num
import Hugs.IO
import Hugs.IOExts
import Hugs.IORef
-import Hugs.Prelude ( throw, Exception(NonTermination) )
+import Hugs.Prelude ( throw, Exception(NonTermination) )
import Control.Exception ( bracket )
-import System.IO.Unsafe ( unsafeInterleaveIO )
+import System.IO.Unsafe ( unsafeInterleaveIO )
#endif
#ifdef __NHC__
-- The file is read lazily, on demand, as with 'getContents'.
readFile :: FilePath -> IO String
-readFile name = openFile name ReadMode >>= hGetContents
+readFile name = openFile name ReadMode >>= hGetContents
-- | The computation 'writeFile' @file str@ function writes the string @str@,
-- to the file @file@.
readIO :: Read a => String -> IO a
readIO s = case (do { (x,t) <- reads s ;
- ("","") <- lex t ;
+ ("","") <- lex t ;
return x }) of
- [x] -> return x
- [] -> ioError (userError "Prelude.readIO: no parse")
- _ -> ioError (userError "Prelude.readIO: ambiguous parse")
+ [x] -> return x
+ [] -> ioError (userError "Prelude.readIO: no parse")
+ _ -> ioError (userError "Prelude.readIO: ambiguous parse")
#endif /* __GLASGOW_HASKELL__ */
#ifndef __NHC__
--
-- * 'System.IO.Error.isEOFError' if the end of file has been reached.
-hReady :: Handle -> IO Bool
-hReady h = hWaitForInput h 0
+hReady :: Handle -> IO Bool
+hReady h = hWaitForInput h 0
-- | The same as 'hPutStr', but adds a newline character.
-hPutStrLn :: Handle -> String -> IO ()
+hPutStrLn :: Handle -> String -> IO ()
hPutStrLn hndl str = do
hPutStr hndl str
hPutChar hndl '\n'
--
-- * 'System.IO.Error.isPermissionError' if another system resource limit would be exceeded.
-hPrint :: Show a => Handle -> a -> IO ()
-hPrint hdl = hPutStrLn hdl . show
+hPrint :: Show a => Handle -> a -> IO ()
+hPrint hdl = hPutStrLn hdl . show
#endif /* !__NHC__ */
-- | @'withFile' name mode act@ opens a file using 'openFile' and passes
hSetBinaryMode _ _ = return ()
#endif
-#ifndef __NHC__
-- | The function creates a temporary file in ReadWrite mode.
-- The created file isn\'t deleted automatically, so you need to delete it manually.
+--
+-- The file is creates with permissions such that only the current
+-- user can read\/write it.
+--
+-- With some exceptions (see below), the file will be created securely
+-- in the sense that an attacker should not be able to cause
+-- openTempFile to overwrite another file on the filesystem using your
+-- credentials, by putting symbolic links (on Unix) in the place where
+-- the temporary file is to be created. On Unix the @O_CREAT@ and
+-- @O_EXCL@ flags are used to prevent this attack, but note that
+-- @O_EXCL@ is sometimes not supported on NFS filesystems, so if you
+-- rely on this behaviour it is best to use local filesystems only.
+--
openTempFile :: FilePath -- ^ Directory in which to create the file
-> String -- ^ File name template. If the template is \"foo.ext\" then
-- the created file will be \"fooXXX.ext\" where XXX is some
-- We split off the last extension, so we can use .foo.ext files
-- for temporary files (hidden on Unix OSes). Unfortunately we're
-- below filepath in the hierarchy here.
- (prefix,suffix) =
+ (prefix,suffix) =
case break (== '.') $ reverse template of
-- First case: template contains no '.'s. Just re-reverse it.
(rev_suffix, "") -> (reverse rev_suffix, "")
-- beginning with '.' as the second component.
_ -> error "bug in System.IO.openTempFile"
+#ifndef __NHC__
oflags1 = rw_flags .|. o_EXCL
binary_flags
| otherwise = 0
oflags = oflags1 .|. binary_flags
+#endif
+#ifdef __NHC__
+ findTempName x = do h <- openFile filepath ReadWriteMode
+ return (filepath, h)
+#else
findTempName x = do
fd <- withCString filepath $ \ f ->
- c_open f oflags 0o666
- if fd < 0
+ c_open f oflags 0o600
+ if fd < 0
then do
errno <- getErrno
if errno == eEXIST
-- as any exceptions etc will only be able to report the
-- fd currently
h <- fdToHandle fd
- `ExceptionBase.catchException` \e -> do c_close fd; throw e
- return (filepath, h)
+ `ExceptionBase.catchAny` \e -> do c_close fd; throw e
+ return (filepath, h)
+#endif
where
filename = prefix ++ show x ++ suffix
- filepath = tmp_dir ++ [pathSeparator] ++ filename
+ filepath = tmp_dir `combine` filename
+
+ -- XXX bits copied from System.FilePath, since that's not available here
+ combine a b
+ | null b = a
+ | null a = b
+ | last a == pathSeparator = a ++ b
+ | otherwise = a ++ [pathSeparator] ++ b
+
#if __HUGS__
fdToHandle fd = openFd (fromIntegral fd) False ReadWriteMode binary
#endif
pathSeparator = '/'
#endif
+#ifndef __NHC__
-- XXX Copied from GHC.Handle
std_flags = o_NONBLOCK .|. o_NOCTTY
output_flags = std_flags .|. o_CREAT
append_flags = write_flags .|. o_APPEND
#endif
+#ifdef __NHC__
+foreign import ccall "getpid" c_getpid :: IO Int
+#endif
+
-- $locking
-- Implementations should enforce as far as possible, at least locally to the
-- Haskell process, multiple-reader single-writer locking on files.
#ifdef __GLASGOW_HASKELL__
-- Copied here to avoid recursive dependency with Control.Exception
-bracket
- :: IO a -- ^ computation to run first (\"acquire resource\")
- -> (a -> IO b) -- ^ computation to run last (\"release resource\")
- -> (a -> IO c) -- ^ computation to run in-between
- -> IO c -- returns the value from the in-between computation
+bracket
+ :: IO a -- ^ computation to run first (\"acquire resource\")
+ -> (a -> IO b) -- ^ computation to run last (\"release resource\")
+ -> (a -> IO c) -- ^ computation to run in-between
+ -> IO c -- returns the value from the in-between computation
bracket before after thing =
block (do
- a <- before
- r <- catchException
- (unblock (thing a))
- (\e -> do { after a; throw e })
+ a <- before
+ r <- catchAny
+ (unblock (thing a))
+ (\e -> do { after a; throw e })
after a
return r
)