2 {-# OPTIONS_HADDOCK hide #-}
4 module Distribution
.Compat
.Internal
.TempFile
11 import Distribution
.Compat
.Exception
13 import System
.FilePath ((</>))
15 import System
.IO (Handle, openBinaryTempFile
, openTempFile
)
16 #if defined
(__IO_MANAGER_WINIO__
)
17 import System
.IO (openBinaryTempFileWithDefaultPermissions
)
19 import Control
.Exception
(onException
)
20 import Data
.Bits
((.|
.))
21 import Foreign
.C
(CInt
, eEXIST
, getErrno
, errnoToIOError
)
22 import GHC
.IO.Handle.FD
(fdToHandle
)
23 import System
.Posix
.Internals
(c_open
, c_close
, o_EXCL
, o_BINARY
, withFilePath
,
24 o_CREAT
, o_RDWR
, o_NONBLOCK
, o_NOCTTY
)
27 import System
.IO.Error
(isAlreadyExistsError)
28 import System
.Posix
.Internals
(c_getpid
)
30 #if defined
(mingw32_HOST_OS
) || defined
(ghcjs_HOST_OS
)
31 import System
.Directory
( createDirectory )
33 import qualified System
.Posix
36 -- ------------------------------------------------------------
40 -- ------------------------------------------------------------
42 -- This is here for Haskell implementations that do not come with
43 -- System.IO.openTempFile. This includes nhc-1.20, hugs-2006.9.
44 -- TODO: This file should probably be removed.
46 -- This is a copy/paste of the openBinaryTempFile definition, but
47 -- it uses 666 rather than 600 for the permissions. Newer versions
48 -- of base have a new function with this behavior which we use on
49 -- Windows when the new IO manager is used.
50 openNewBinaryFile
:: FilePath -> String -> IO (FilePath, Handle)
51 openNewBinaryFile dir template
= do
53 -- This method can't be used under WINIO. Also the current implementation has
54 -- thread safety issues depending on which GHC is used. On newer GHC's let's
55 -- use the built in one.
56 #if defined
(__IO_MANAGER_WINIO__
)
57 openBinaryTempFileWithDefaultPermissions dir template
62 -- We split off the last extension, so we can use .foo.ext files
63 -- for temporary files (hidden on Unix OSes). Unfortunately we're
64 -- below file path in the hierarchy here.
66 case break (== '.') $ reverse template
of
67 -- First case: template contains no '.'s. Just re-reverse it.
68 (rev_suffix
, "") -> (reverse rev_suffix
, "")
69 -- Second case: template contains at least one '.'. Strip the
70 -- dot from the prefix and prepend it to the suffix (if we don't
71 -- do this, the unique number will get added after the '.' and
72 -- thus be part of the extension, which is wrong.)
73 (rev_suffix
, '.':rest
) -> (reverse rest
, '.':reverse rev_suffix
)
74 -- Otherwise, something is wrong, because (break (== '.')) should
75 -- always return a pair with either the empty string or a string
76 -- beginning with '.' as the second component.
77 _
-> error "bug in System.IO.openTempFile"
79 oflags
= rw_flags
.|
. o_EXCL
.|
. o_BINARY
82 fd
<- withFilePath filepath
$ \ f
->
88 then findTempName
(x
+1)
89 else ioError (errnoToIOError
"openNewBinaryFile" errno Nothing
(Just dir
))
91 -- TODO: We want to tell fdToHandle what the file path is,
92 -- as any exceptions etc will only be able to report the
94 h
<- fdToHandle fd `onException` c_close fd
97 filename
= prefix
++ show x
++ suffix
98 filepath
= dir `combine` filename
100 -- FIXME: bits copied from System.FilePath
104 |
last a
== pathSeparator
= a
++ b
105 |
otherwise = a
++ [pathSeparator
] ++ b
107 -- FIXME: Copied from GHC.Handle
108 std_flags
, output_flags
, rw_flags
:: CInt
109 std_flags
= o_NONBLOCK
.|
. o_NOCTTY
110 output_flags
= std_flags
.|
. o_CREAT
111 rw_flags
= output_flags
.|
. o_RDWR
113 -- FIXME: Should use System.FilePath library
114 pathSeparator
:: Char
115 #ifdef mingw32_HOST_OS
120 -- /* __IO_MANAGER_WINIO__ */
123 createTempDirectory
:: FilePath -> String -> IO FilePath
124 createTempDirectory dir template
= do
129 let relpath
= template
++ "-" ++ show x
130 dirpath
= dir
</> relpath
131 r
<- tryIO
$ mkPrivateDir dirpath
133 Right _
-> return relpath
135 |
isAlreadyExistsError e
-> findTempName
(x
+ 1)
136 |
otherwise -> ioError e
138 mkPrivateDir
:: String -> IO ()
139 #if defined
(mingw32_HOST_OS
) || defined
(ghcjs_HOST_OS
)
140 mkPrivateDir s
= createDirectory s
142 mkPrivateDir s
= System
.Posix
.createDirectory s
0o700