+{- |@'copyFile' old new@ copies the existing file from /old/ to /new/.
+If the /new/ file already exists, it is atomically replaced by the /old/ file.
+Neither path may refer to an existing directory. The permissions of /old/ are
+copied to /new/, if possible.
+-}
+
+copyFile :: FilePath -> FilePath -> IO ()
+#ifdef __NHC__
+copyFile fromFPath toFPath =
+ do readFile fromFPath >>= writeFile toFPath
+ Prelude.catch (copyPermissions fromFPath toFPath)
+ (\_ -> return ())
+#else
+copyFile fromFPath toFPath =
+ copy `Prelude.catch` (\exc -> throw $ ioeSetLocation exc "copyFile")
+ where copy = bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
+ bracketOnError openTmp cleanTmp $ \(tmpFPath, hTmp) ->
+ do allocaBytes bufferSize $ copyContents hFrom hTmp
+ hClose hTmp
+ ignoreIOExceptions $ copyPermissions fromFPath tmpFPath
+ renameFile tmpFPath toFPath
+ openTmp = openBinaryTempFile (takeDirectory toFPath) ".copyFile.tmp"
+ cleanTmp (tmpFPath, hTmp)
+ = do ignoreIOExceptions $ hClose hTmp
+ ignoreIOExceptions $ removeFile tmpFPath
+ bufferSize = 1024
+
+ copyContents hFrom hTo buffer = do
+ count <- hGetBuf hFrom buffer bufferSize
+ when (count > 0) $ do
+ hPutBuf hTo buffer count
+ copyContents hFrom hTo buffer
+
+ ignoreIOExceptions io = io `catch` ioExceptionIgnorer
+ ioExceptionIgnorer :: IOException -> IO ()
+ ioExceptionIgnorer _ = return ()
+#endif
+
+-- | Given path referring to a file or directory, returns a
+-- canonicalized path, with the intent that two paths referring
+-- to the same file\/directory will map to the same canonicalized
+-- path. Note that it is impossible to guarantee that the
+-- implication (same file\/dir \<=\> same canonicalizedPath) holds
+-- in either direction: this function can make only a best-effort
+-- attempt.
+canonicalizePath :: FilePath -> IO FilePath
+canonicalizePath fpath =
+#if defined(mingw32_HOST_OS)
+ do path <- Win32.getFullPathName fpath
+#else
+ withCString fpath $ \pInPath ->
+ allocaBytes long_path_size $ \pOutPath ->
+ do throwErrnoPathIfNull "canonicalizePath" fpath $ c_realpath pInPath pOutPath
+ path <- peekCString pOutPath
+#endif
+ return (normalise path)
+ -- normalise does more stuff, like upper-casing the drive letter
+
+#if !defined(mingw32_HOST_OS)
+foreign import ccall unsafe "realpath"
+ c_realpath :: CString
+ -> CString
+ -> IO CString
+#endif